# Note for reviewer

Most changes are just syntax changes necessary for the new version.
Most important files should be the ones under the `xcm` folder.

# Description 

Added XCMv4.

## Removed `Multi` prefix
The following types have been renamed:
- MultiLocation -> Location
- MultiAsset -> Asset
- MultiAssets -> Assets
- InteriorMultiLocation -> InteriorLocation
- MultiAssetFilter -> AssetFilter
- VersionedMultiAsset -> VersionedAsset
- WildMultiAsset -> WildAsset
- VersionedMultiLocation -> VersionedLocation

In order to fix a name conflict, the `Assets` in `xcm-executor` were
renamed to `HoldingAssets`, as they represent assets in holding.

## Removed `Abstract` asset id

It was not being used anywhere and this simplifies the code.

Now assets are just constructed as follows:

```rust
let asset: Asset = (AssetId(Location::new(1, Here)), 100u128).into();
```

No need for specifying `Concrete` anymore.

## Outcome is now a named fields struct

Instead of

```rust
pub enum Outcome {
  Complete(Weight),
  Incomplete(Weight, Error),
  Error(Error),
}
```

we now have

```rust
pub enum Outcome {
  Complete { used: Weight },
  Incomplete { used: Weight, error: Error },
  Error { error: Error },
}
```

## Added Reanchorable trait

Now both locations and assets implement this trait, making it easier to
reanchor both.

## New syntax for building locations and junctions

Now junctions are built using the following methods:

```rust
let location = Location {
    parents: 1,
    interior: [Parachain(1000), PalletInstance(50), GeneralIndex(1984)].into()
};
```

or

```rust
let location = Location::new(1, [Parachain(1000), PalletInstance(50), GeneralIndex(1984)]);
```

And they are matched like so:

```rust
match location.unpack() {
  (1, [Parachain(id)]) => ...
  (0, Here) => ...,
  (1, [_]) => ...,
}
```

This syntax is mandatory in v4, and has been also implemented for v2 and
v3 for easier migration.

This was needed to make all sizes smaller.

# TODO
- [x] Scaffold v4
- [x] Port github.com/paritytech/polkadot/pull/7236
- [x] Remove `Multi` prefix
- [x] Remove `Abstract` asset id

---------

Co-authored-by: command-bot <>
Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>
This commit is contained in:
Francisco Aguirre
2024-01-16 19:18:04 +01:00
committed by GitHub
parent ec7bfae00a
commit 8428f678fe
255 changed files with 12425 additions and 6726 deletions
+70 -100
View File
@@ -23,39 +23,42 @@ use xcm::latest::prelude::*;
use xcm_executor::traits::{Error as MatchError, MatchesFungibles, MatchesNonFungibles};
/// 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)>,
/// `TryFrom/TryInto<u128>`) into a `GeneralIndex` junction, prefixed by some `Location` value.
/// The `Location` value will typically be a `PalletInstance` junction.
pub struct AsPrefixedGeneralIndex<Prefix, AssetId, ConvertAssetId, L = Location>(
PhantomData<(Prefix, AssetId, ConvertAssetId, L)>,
);
impl<
Prefix: Get<MultiLocation>,
Prefix: Get<L>,
AssetId: Clone,
ConvertAssetId: MaybeEquivalence<u128, AssetId>,
> MaybeEquivalence<MultiLocation, AssetId>
for AsPrefixedGeneralIndex<Prefix, AssetId, ConvertAssetId>
L: TryInto<Location> + TryFrom<Location> + Clone,
> MaybeEquivalence<L, AssetId> for AsPrefixedGeneralIndex<Prefix, AssetId, ConvertAssetId, L>
{
fn convert(id: &MultiLocation) -> Option<AssetId> {
fn convert(id: &L) -> Option<AssetId> {
let prefix = Prefix::get();
if prefix.parent_count() != id.parent_count() ||
prefix
let latest_prefix: Location = prefix.try_into().ok()?;
let latest_id: Location = (*id).clone().try_into().ok()?;
if latest_prefix.parent_count() != latest_id.parent_count() ||
latest_prefix
.interior()
.iter()
.enumerate()
.any(|(index, junction)| id.interior().at(index) != Some(junction))
.any(|(index, junction)| latest_id.interior().at(index) != Some(junction))
{
return None
}
match id.interior().at(prefix.interior().len()) {
Some(Junction::GeneralIndex(id)) => ConvertAssetId::convert(id),
match latest_id.interior().at(latest_prefix.interior().len()) {
Some(Junction::GeneralIndex(id)) => ConvertAssetId::convert(&id),
_ => None,
}
}
fn convert_back(what: &AssetId) -> Option<MultiLocation> {
let mut location = Prefix::get();
fn convert_back(what: &AssetId) -> Option<L> {
let location = Prefix::get();
let mut latest_location: Location = location.try_into().ok()?;
let id = ConvertAssetId::convert_back(what)?;
location.push_interior(Junction::GeneralIndex(id)).ok()?;
Some(location)
latest_location.push_interior(Junction::GeneralIndex(id)).ok()?;
latest_location.try_into().ok()
}
}
@@ -65,14 +68,14 @@ pub struct ConvertedConcreteId<AssetId, Balance, ConvertAssetId, ConvertOther>(
impl<
AssetId: Clone,
Balance: Clone,
ConvertAssetId: MaybeEquivalence<MultiLocation, AssetId>,
ConvertAssetId: MaybeEquivalence<Location, AssetId>,
ConvertBalance: MaybeEquivalence<u128, Balance>,
> MatchesFungibles<AssetId, Balance>
for ConvertedConcreteId<AssetId, Balance, ConvertAssetId, ConvertBalance>
{
fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), MatchError> {
fn matches_fungibles(a: &Asset) -> result::Result<(AssetId, Balance), MatchError> {
let (amount, id) = match (&a.fun, &a.id) {
(Fungible(ref amount), Concrete(ref id)) => (amount, id),
(Fungible(ref amount), AssetId(ref id)) => (amount, id),
_ => return Err(MatchError::AssetNotHandled),
};
let what = ConvertAssetId::convert(id).ok_or(MatchError::AssetIdConversionFailed)?;
@@ -84,56 +87,14 @@ impl<
impl<
ClassId: Clone,
InstanceId: Clone,
ConvertClassId: MaybeEquivalence<MultiLocation, ClassId>,
ConvertClassId: MaybeEquivalence<Location, ClassId>,
ConvertInstanceId: MaybeEquivalence<AssetInstance, InstanceId>,
> MatchesNonFungibles<ClassId, InstanceId>
for ConvertedConcreteId<ClassId, InstanceId, ConvertClassId, ConvertInstanceId>
{
fn matches_nonfungibles(a: &MultiAsset) -> result::Result<(ClassId, InstanceId), MatchError> {
fn matches_nonfungibles(a: &Asset) -> result::Result<(ClassId, InstanceId), MatchError> {
let (instance, class) = match (&a.fun, &a.id) {
(NonFungible(ref instance), Concrete(ref class)) => (instance, class),
_ => return Err(MatchError::AssetNotHandled),
};
let what = ConvertClassId::convert(class).ok_or(MatchError::AssetIdConversionFailed)?;
let instance =
ConvertInstanceId::convert(instance).ok_or(MatchError::InstanceConversionFailed)?;
Ok((what, instance))
}
}
pub struct ConvertedAbstractId<AssetId, Balance, ConvertAssetId, ConvertOther>(
PhantomData<(AssetId, Balance, ConvertAssetId, ConvertOther)>,
);
impl<
AssetId: Clone,
Balance: Clone,
ConvertAssetId: MaybeEquivalence<[u8; 32], AssetId>,
ConvertBalance: MaybeEquivalence<u128, Balance>,
> MatchesFungibles<AssetId, Balance>
for ConvertedAbstractId<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::AssetNotHandled),
};
let what = ConvertAssetId::convert(id).ok_or(MatchError::AssetIdConversionFailed)?;
let amount =
ConvertBalance::convert(amount).ok_or(MatchError::AmountToBalanceConversionFailed)?;
Ok((what, amount))
}
}
impl<
ClassId: Clone,
InstanceId: Clone,
ConvertClassId: MaybeEquivalence<[u8; 32], ClassId>,
ConvertInstanceId: MaybeEquivalence<AssetInstance, InstanceId>,
> MatchesNonFungibles<ClassId, InstanceId>
for ConvertedAbstractId<ClassId, InstanceId, ConvertClassId, ConvertInstanceId>
{
fn matches_nonfungibles(a: &MultiAsset) -> result::Result<(ClassId, InstanceId), MatchError> {
let (instance, class) = match (&a.fun, &a.id) {
(NonFungible(ref instance), Abstract(ref class)) => (instance, class),
(NonFungible(ref instance), AssetId(ref class)) => (instance, class),
_ => return Err(MatchError::AssetNotHandled),
};
let what = ConvertClassId::convert(class).ok_or(MatchError::AssetIdConversionFailed)?;
@@ -145,8 +106,17 @@ impl<
#[deprecated = "Use `ConvertedConcreteId` instead"]
pub type ConvertedConcreteAssetId<A, B, C, O> = ConvertedConcreteId<A, B, C, O>;
#[deprecated = "Use `ConvertedAbstractId` instead"]
pub type ConvertedAbstractAssetId<A, B, C, O> = ConvertedAbstractId<A, B, C, O>;
pub struct V4V3LocationConverter;
impl MaybeEquivalence<xcm::v4::Location, xcm::v3::Location> for V4V3LocationConverter {
fn convert(old: &xcm::v4::Location) -> Option<xcm::v3::Location> {
(*old).clone().try_into().ok()
}
fn convert_back(new: &xcm::v3::Location) -> Option<xcm::v4::Location> {
(*new).try_into().ok()
}
}
pub struct MatchedConvertedConcreteId<AssetId, Balance, MatchAssetId, ConvertAssetId, ConvertOther>(
PhantomData<(AssetId, Balance, MatchAssetId, ConvertAssetId, ConvertOther)>,
@@ -154,15 +124,15 @@ pub struct MatchedConvertedConcreteId<AssetId, Balance, MatchAssetId, ConvertAss
impl<
AssetId: Clone,
Balance: Clone,
MatchAssetId: Contains<MultiLocation>,
ConvertAssetId: MaybeEquivalence<MultiLocation, AssetId>,
MatchAssetId: Contains<Location>,
ConvertAssetId: MaybeEquivalence<Location, AssetId>,
ConvertBalance: MaybeEquivalence<u128, Balance>,
> MatchesFungibles<AssetId, Balance>
for MatchedConvertedConcreteId<AssetId, Balance, MatchAssetId, ConvertAssetId, ConvertBalance>
{
fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), MatchError> {
fn matches_fungibles(a: &Asset) -> result::Result<(AssetId, Balance), MatchError> {
let (amount, id) = match (&a.fun, &a.id) {
(Fungible(ref amount), Concrete(ref id)) if MatchAssetId::contains(id) => (amount, id),
(Fungible(ref amount), AssetId(ref id)) if MatchAssetId::contains(id) => (amount, id),
_ => return Err(MatchError::AssetNotHandled),
};
let what = ConvertAssetId::convert(id).ok_or(MatchError::AssetIdConversionFailed)?;
@@ -174,15 +144,15 @@ impl<
impl<
ClassId: Clone,
InstanceId: Clone,
MatchClassId: Contains<MultiLocation>,
ConvertClassId: MaybeEquivalence<MultiLocation, ClassId>,
MatchClassId: Contains<Location>,
ConvertClassId: MaybeEquivalence<Location, ClassId>,
ConvertInstanceId: MaybeEquivalence<AssetInstance, InstanceId>,
> MatchesNonFungibles<ClassId, InstanceId>
for MatchedConvertedConcreteId<ClassId, InstanceId, MatchClassId, ConvertClassId, ConvertInstanceId>
{
fn matches_nonfungibles(a: &MultiAsset) -> result::Result<(ClassId, InstanceId), MatchError> {
fn matches_nonfungibles(a: &Asset) -> result::Result<(ClassId, InstanceId), MatchError> {
let (instance, class) = match (&a.fun, &a.id) {
(NonFungible(ref instance), Concrete(ref class)) if MatchClassId::contains(class) =>
(NonFungible(ref instance), AssetId(ref class)) if MatchClassId::contains(class) =>
(instance, class),
_ => return Err(MatchError::AssetNotHandled),
};
@@ -200,10 +170,10 @@ mod tests {
use xcm_executor::traits::JustTry;
struct OnlyParentZero;
impl Contains<MultiLocation> for OnlyParentZero {
fn contains(a: &MultiLocation) -> bool {
impl Contains<Location> for OnlyParentZero {
fn contains(a: &Location) -> bool {
match a {
MultiLocation { parents: 0, .. } => true,
Location { parents: 0, .. } => true,
_ => false,
}
}
@@ -214,7 +184,7 @@ mod tests {
type AssetIdForTrustBackedAssets = u32;
type Balance = u128;
frame_support::parameter_types! {
pub TrustBackedAssetsPalletLocation: MultiLocation = PalletInstance(50).into();
pub TrustBackedAssetsPalletLocation: Location = PalletInstance(50).into();
}
// ConvertedConcreteId cfg
@@ -231,13 +201,13 @@ mod tests {
>;
assert_eq!(
TrustBackedAssetsPalletLocation::get(),
MultiLocation { parents: 0, interior: X1(PalletInstance(50)) }
Location { parents: 0, interior: [PalletInstance(50)].into() }
);
// err - does not match
assert_eq!(
Converter::matches_fungibles(&MultiAsset {
id: Concrete(MultiLocation::new(1, X2(PalletInstance(50), GeneralIndex(1)))),
Converter::matches_fungibles(&Asset {
id: AssetId(Location::new(1, [PalletInstance(50), GeneralIndex(1)])),
fun: Fungible(12345),
}),
Err(MatchError::AssetNotHandled)
@@ -245,10 +215,10 @@ mod tests {
// err - matches, but convert fails
assert_eq!(
Converter::matches_fungibles(&MultiAsset {
id: Concrete(MultiLocation::new(
Converter::matches_fungibles(&Asset {
id: AssetId(Location::new(
0,
X2(PalletInstance(50), GeneralKey { length: 1, data: [1; 32] })
[PalletInstance(50), GeneralKey { length: 1, data: [1; 32] }]
)),
fun: Fungible(12345),
}),
@@ -257,8 +227,8 @@ mod tests {
// err - matches, but NonFungible
assert_eq!(
Converter::matches_fungibles(&MultiAsset {
id: Concrete(MultiLocation::new(0, X2(PalletInstance(50), GeneralIndex(1)))),
Converter::matches_fungibles(&Asset {
id: AssetId(Location::new(0, [PalletInstance(50), GeneralIndex(1)])),
fun: NonFungible(Index(54321)),
}),
Err(MatchError::AssetNotHandled)
@@ -266,8 +236,8 @@ mod tests {
// ok
assert_eq!(
Converter::matches_fungibles(&MultiAsset {
id: Concrete(MultiLocation::new(0, X2(PalletInstance(50), GeneralIndex(1)))),
Converter::matches_fungibles(&Asset {
id: AssetId(Location::new(0, [PalletInstance(50), GeneralIndex(1)])),
fun: Fungible(12345),
}),
Ok((1, 12345))
@@ -279,7 +249,7 @@ mod tests {
type ClassId = u32;
type ClassInstanceId = u64;
frame_support::parameter_types! {
pub TrustBackedAssetsPalletLocation: MultiLocation = PalletInstance(50).into();
pub TrustBackedAssetsPalletLocation: Location = PalletInstance(50).into();
}
// ConvertedConcreteId cfg
@@ -303,13 +273,13 @@ mod tests {
>;
assert_eq!(
TrustBackedAssetsPalletLocation::get(),
MultiLocation { parents: 0, interior: X1(PalletInstance(50)) }
Location { parents: 0, interior: [PalletInstance(50)].into() }
);
// err - does not match
assert_eq!(
Converter::matches_nonfungibles(&MultiAsset {
id: Concrete(MultiLocation::new(1, X2(PalletInstance(50), GeneralIndex(1)))),
Converter::matches_nonfungibles(&Asset {
id: AssetId(Location::new(1, [PalletInstance(50), GeneralIndex(1)])),
fun: NonFungible(Index(54321)),
}),
Err(MatchError::AssetNotHandled)
@@ -317,10 +287,10 @@ mod tests {
// err - matches, but convert fails
assert_eq!(
Converter::matches_nonfungibles(&MultiAsset {
id: Concrete(MultiLocation::new(
Converter::matches_nonfungibles(&Asset {
id: AssetId(Location::new(
0,
X2(PalletInstance(50), GeneralKey { length: 1, data: [1; 32] })
[PalletInstance(50), GeneralKey { length: 1, data: [1; 32] }]
)),
fun: NonFungible(Index(54321)),
}),
@@ -329,8 +299,8 @@ mod tests {
// err - matches, but Fungible vs NonFungible
assert_eq!(
Converter::matches_nonfungibles(&MultiAsset {
id: Concrete(MultiLocation::new(0, X2(PalletInstance(50), GeneralIndex(1)))),
Converter::matches_nonfungibles(&Asset {
id: AssetId(Location::new(0, [PalletInstance(50), GeneralIndex(1)])),
fun: Fungible(12345),
}),
Err(MatchError::AssetNotHandled)
@@ -338,8 +308,8 @@ mod tests {
// ok
assert_eq!(
Converter::matches_nonfungibles(&MultiAsset {
id: Concrete(MultiLocation::new(0, X2(PalletInstance(50), GeneralIndex(1)))),
Converter::matches_nonfungibles(&Asset {
id: AssetId(Location::new(0, [PalletInstance(50), GeneralIndex(1)])),
fun: NonFungible(Index(54321)),
}),
Ok((1, 54321))
+29 -35
View File
@@ -34,7 +34,7 @@ use xcm_executor::traits::{CheckSuspension, OnResponse, Properties, ShouldExecut
pub struct TakeWeightCredit;
impl ShouldExecute for TakeWeightCredit {
fn should_execute<RuntimeCall>(
_origin: &MultiLocation,
_origin: &Location,
_instructions: &mut [Instruction<RuntimeCall>],
max_weight: Weight,
properties: &mut Properties,
@@ -60,9 +60,9 @@ const MAX_ASSETS_FOR_BUY_EXECUTION: usize = 2;
/// Only allows for `TeleportAsset`, `WithdrawAsset`, `ClaimAsset` and `ReserveAssetDeposit` XCMs
/// because they are the only ones that place assets in the Holding Register to pay for execution.
pub struct AllowTopLevelPaidExecutionFrom<T>(PhantomData<T>);
impl<T: Contains<MultiLocation>> ShouldExecute for AllowTopLevelPaidExecutionFrom<T> {
impl<T: Contains<Location>> ShouldExecute for AllowTopLevelPaidExecutionFrom<T> {
fn should_execute<RuntimeCall>(
origin: &MultiLocation,
origin: &Location,
instructions: &mut [Instruction<RuntimeCall>],
max_weight: Weight,
_properties: &mut Properties,
@@ -158,14 +158,11 @@ impl<T: Contains<MultiLocation>> ShouldExecute for AllowTopLevelPaidExecutionFro
pub struct WithComputedOrigin<InnerBarrier, LocalUniversal, MaxPrefixes>(
PhantomData<(InnerBarrier, LocalUniversal, MaxPrefixes)>,
);
impl<
InnerBarrier: ShouldExecute,
LocalUniversal: Get<InteriorMultiLocation>,
MaxPrefixes: Get<u32>,
> ShouldExecute for WithComputedOrigin<InnerBarrier, LocalUniversal, MaxPrefixes>
impl<InnerBarrier: ShouldExecute, LocalUniversal: Get<InteriorLocation>, MaxPrefixes: Get<u32>>
ShouldExecute for WithComputedOrigin<InnerBarrier, LocalUniversal, MaxPrefixes>
{
fn should_execute<Call>(
origin: &MultiLocation,
origin: &Location,
instructions: &mut [Instruction<Call>],
max_weight: Weight,
properties: &mut Properties,
@@ -175,7 +172,7 @@ impl<
"WithComputedOrigin origin: {:?}, instructions: {:?}, max_weight: {:?}, properties: {:?}",
origin, instructions, max_weight, properties,
);
let mut actual_origin = *origin;
let mut actual_origin = origin.clone();
let skipped = Cell::new(0usize);
// NOTE: We do not check the validity of `UniversalOrigin` here, meaning that a malicious
// origin could place a `UniversalOrigin` in order to spoof some location which gets free
@@ -190,10 +187,11 @@ impl<
// Note the origin is *relative to local consensus*! So we need to escape
// local consensus with the `parents` before diving in into the
// `universal_location`.
actual_origin = X1(*new_global).relative_to(&LocalUniversal::get());
actual_origin =
Junctions::from([*new_global]).relative_to(&LocalUniversal::get());
},
DescendOrigin(j) => {
let Ok(_) = actual_origin.append_with(*j) else {
let Ok(_) = actual_origin.append_with(j.clone()) else {
return Err(ProcessMessageError::Unsupported)
};
},
@@ -221,7 +219,7 @@ impl<
pub struct TrailingSetTopicAsId<InnerBarrier>(PhantomData<InnerBarrier>);
impl<InnerBarrier: ShouldExecute> ShouldExecute for TrailingSetTopicAsId<InnerBarrier> {
fn should_execute<Call>(
origin: &MultiLocation,
origin: &Location,
instructions: &mut [Instruction<Call>],
max_weight: Weight,
properties: &mut Properties,
@@ -250,7 +248,7 @@ where
SuspensionChecker: CheckSuspension,
{
fn should_execute<Call>(
origin: &MultiLocation,
origin: &Location,
instructions: &mut [Instruction<Call>],
max_weight: Weight,
properties: &mut Properties,
@@ -268,9 +266,9 @@ where
/// Use only for executions from completely trusted origins, from which no permissionless messages
/// can be sent.
pub struct AllowUnpaidExecutionFrom<T>(PhantomData<T>);
impl<T: Contains<MultiLocation>> ShouldExecute for AllowUnpaidExecutionFrom<T> {
impl<T: Contains<Location>> ShouldExecute for AllowUnpaidExecutionFrom<T> {
fn should_execute<RuntimeCall>(
origin: &MultiLocation,
origin: &Location,
instructions: &mut [Instruction<RuntimeCall>],
_max_weight: Weight,
_properties: &mut Properties,
@@ -290,9 +288,9 @@ impl<T: Contains<MultiLocation>> ShouldExecute for AllowUnpaidExecutionFrom<T> {
///
/// Use only for executions from trusted origin groups.
pub struct AllowExplicitUnpaidExecutionFrom<T>(PhantomData<T>);
impl<T: Contains<MultiLocation>> ShouldExecute for AllowExplicitUnpaidExecutionFrom<T> {
impl<T: Contains<Location>> ShouldExecute for AllowExplicitUnpaidExecutionFrom<T> {
fn should_execute<Call>(
origin: &MultiLocation,
origin: &Location,
instructions: &mut [Instruction<Call>],
max_weight: Weight,
_properties: &mut Properties,
@@ -314,11 +312,11 @@ impl<T: Contains<MultiLocation>> ShouldExecute for AllowExplicitUnpaidExecutionF
/// 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> {
fn contains(l: &MultiLocation) -> bool {
impl<ParaId: IsSystem + From<u32>> Contains<Location> for IsChildSystemParachain<ParaId> {
fn contains(l: &Location) -> bool {
matches!(
l.interior(),
Junctions::X1(Junction::Parachain(id))
l.interior().as_slice(),
[Junction::Parachain(id)]
if ParaId::from(*id).is_system() && l.parent_count() == 0,
)
}
@@ -328,7 +326,7 @@ impl<ParaId: IsSystem + From<u32>> Contains<MultiLocation> for IsChildSystemPara
pub struct AllowKnownQueryResponses<ResponseHandler>(PhantomData<ResponseHandler>);
impl<ResponseHandler: OnResponse> ShouldExecute for AllowKnownQueryResponses<ResponseHandler> {
fn should_execute<RuntimeCall>(
origin: &MultiLocation,
origin: &Location,
instructions: &mut [Instruction<RuntimeCall>],
_max_weight: Weight,
_properties: &mut Properties,
@@ -354,9 +352,9 @@ impl<ResponseHandler: OnResponse> ShouldExecute for AllowKnownQueryResponses<Res
/// Allows execution from `origin` if it is just a straight `SubscribeVersion` or
/// `UnsubscribeVersion` instruction.
pub struct AllowSubscriptionsFrom<T>(PhantomData<T>);
impl<T: Contains<MultiLocation>> ShouldExecute for AllowSubscriptionsFrom<T> {
impl<T: Contains<Location>> ShouldExecute for AllowSubscriptionsFrom<T> {
fn should_execute<RuntimeCall>(
origin: &MultiLocation,
origin: &Location,
instructions: &mut [Instruction<RuntimeCall>],
_max_weight: Weight,
_properties: &mut Properties,
@@ -391,7 +389,7 @@ where
Allow: ShouldExecute,
{
fn should_execute<RuntimeCall>(
origin: &MultiLocation,
origin: &Location,
message: &mut [Instruction<RuntimeCall>],
max_weight: Weight,
properties: &mut Properties,
@@ -405,7 +403,7 @@ where
pub struct DenyReserveTransferToRelayChain;
impl ShouldExecute for DenyReserveTransferToRelayChain {
fn should_execute<RuntimeCall>(
origin: &MultiLocation,
origin: &Location,
message: &mut [Instruction<RuntimeCall>],
_max_weight: Weight,
_properties: &mut Properties,
@@ -414,22 +412,18 @@ impl ShouldExecute for DenyReserveTransferToRelayChain {
|_| true,
|inst| match inst {
InitiateReserveWithdraw {
reserve: MultiLocation { parents: 1, interior: Here },
reserve: Location { parents: 1, interior: Here },
..
} |
DepositReserveAsset {
dest: MultiLocation { parents: 1, interior: Here }, ..
} |
TransferReserveAsset {
dest: MultiLocation { parents: 1, interior: Here }, ..
} => {
DepositReserveAsset { dest: Location { parents: 1, interior: Here }, .. } |
TransferReserveAsset { dest: Location { parents: 1, interior: Here }, .. } => {
Err(ProcessMessageError::Unsupported) // Deny
},
// An unexpected reserve transfer has arrived from the Relay Chain. Generally,
// `IsReserve` should not allow this, but we just log it here.
ReserveAssetDeposited { .. }
if matches!(origin, MultiLocation { parents: 1, interior: Here }) =>
if matches!(origin, Location { parents: 1, interior: Here }) =>
{
log::warn!(
target: "xcm::barrier",
+6 -6
View File
@@ -45,7 +45,7 @@ pub trait ExecuteControllerWeightInfo {
/// Execute an XCM locally, for a given origin.
///
/// An implementation of that trait will handle the low-level details of the execution, such as:
/// - Validating and Converting the origin to a MultiLocation.
/// - Validating and Converting the origin to a Location.
/// - Handling versioning.
/// - Calling the internal executor, which implements [`ExecuteXcm`].
pub trait ExecuteController<Origin, RuntimeCall> {
@@ -92,7 +92,7 @@ pub trait SendController<Origin> {
/// - `msg`: the XCM to be sent.
fn send(
origin: Origin,
dest: Box<VersionedMultiLocation>,
dest: Box<VersionedLocation>,
message: Box<VersionedXcm<()>>,
) -> Result<XcmHash, DispatchError>;
}
@@ -127,7 +127,7 @@ pub trait QueryController<Origin, Timeout>: QueryHandler {
fn query(
origin: Origin,
timeout: Timeout,
match_querier: VersionedMultiLocation,
match_querier: VersionedLocation,
) -> Result<Self::QueryId, DispatchError>;
}
@@ -138,7 +138,7 @@ impl<Origin, RuntimeCall> ExecuteController<Origin, RuntimeCall> for () {
_message: Box<VersionedXcm<RuntimeCall>>,
_max_weight: Weight,
) -> Result<Outcome, DispatchError> {
Ok(Outcome::Error(XcmError::Unimplemented))
Ok(Outcome::Error { error: XcmError::Unimplemented })
}
}
@@ -152,7 +152,7 @@ impl<Origin> SendController<Origin> for () {
type WeightInfo = ();
fn send(
_origin: Origin,
_dest: Box<VersionedMultiLocation>,
_dest: Box<VersionedLocation>,
_message: Box<VersionedXcm<()>>,
) -> Result<XcmHash, DispatchError> {
Ok(Default::default())
@@ -180,7 +180,7 @@ impl<Origin, Timeout> QueryController<Origin, Timeout> for () {
fn query(
_origin: Origin,
_timeout: Timeout,
_match_querier: VersionedMultiLocation,
_match_querier: VersionedLocation,
) -> Result<Self::QueryId, DispatchError> {
Ok(Default::default())
}
@@ -22,17 +22,17 @@ use super::MintLocation;
use frame_support::traits::{ExistenceRequirement::AllowDeath, Get, WithdrawReasons};
use sp_runtime::traits::CheckedSub;
use sp_std::{marker::PhantomData, result};
use xcm::latest::{Error as XcmError, MultiAsset, MultiLocation, Result, XcmContext};
use xcm::latest::{Asset, Error as XcmError, Location, Result, XcmContext};
use xcm_executor::{
traits::{ConvertLocation, MatchesFungible, TransactAsset},
Assets,
AssetsInHolding,
};
/// Asset transaction errors.
enum Error {
/// The given asset is not handled. (According to [`XcmError::AssetNotFound`])
AssetNotHandled,
/// `MultiLocation` to `AccountId` conversion failed.
/// `Location` to `AccountId` conversion failed.
AccountIdConversionFailed,
}
@@ -62,7 +62,7 @@ impl From<Error> for XcmError {
///
/// /// Our relay chain's location.
/// parameter_types! {
/// pub RelayChain: MultiLocation = Parent.into();
/// pub RelayChain: Location = Parent.into();
/// pub CheckingAccount: AccountId = PalletId(*b"checking").into_account_truncating();
/// }
///
@@ -142,7 +142,7 @@ impl<
> TransactAsset
for CurrencyAdapter<Currency, Matcher, AccountIdConverter, AccountId, CheckedAccount>
{
fn can_check_in(_origin: &MultiLocation, what: &MultiAsset, _context: &XcmContext) -> Result {
fn can_check_in(_origin: &Location, what: &Asset, _context: &XcmContext) -> Result {
log::trace!(target: "xcm::currency_adapter", "can_check_in origin: {:?}, what: {:?}", _origin, what);
// Check we handle this asset.
let amount: Currency::Balance =
@@ -156,7 +156,7 @@ impl<
}
}
fn check_in(_origin: &MultiLocation, what: &MultiAsset, _context: &XcmContext) {
fn check_in(_origin: &Location, what: &Asset, _context: &XcmContext) {
log::trace!(target: "xcm::currency_adapter", "check_in origin: {:?}, what: {:?}", _origin, what);
if let Some(amount) = Matcher::matches_fungible(what) {
match CheckedAccount::get() {
@@ -169,7 +169,7 @@ impl<
}
}
fn can_check_out(_dest: &MultiLocation, what: &MultiAsset, _context: &XcmContext) -> Result {
fn can_check_out(_dest: &Location, what: &Asset, _context: &XcmContext) -> Result {
log::trace!(target: "xcm::currency_adapter", "check_out dest: {:?}, what: {:?}", _dest, what);
let amount = Matcher::matches_fungible(what).ok_or(Error::AssetNotHandled)?;
match CheckedAccount::get() {
@@ -181,7 +181,7 @@ impl<
}
}
fn check_out(_dest: &MultiLocation, what: &MultiAsset, _context: &XcmContext) {
fn check_out(_dest: &Location, what: &Asset, _context: &XcmContext) {
log::trace!(target: "xcm::currency_adapter", "check_out dest: {:?}, what: {:?}", _dest, what);
if let Some(amount) = Matcher::matches_fungible(what) {
match CheckedAccount::get() {
@@ -194,11 +194,7 @@ impl<
}
}
fn deposit_asset(
what: &MultiAsset,
who: &MultiLocation,
_context: Option<&XcmContext>,
) -> Result {
fn deposit_asset(what: &Asset, who: &Location, _context: Option<&XcmContext>) -> Result {
log::trace!(target: "xcm::currency_adapter", "deposit_asset what: {:?}, who: {:?}", what, who);
// Check we handle this asset.
let amount = Matcher::matches_fungible(&what).ok_or(Error::AssetNotHandled)?;
@@ -209,10 +205,10 @@ impl<
}
fn withdraw_asset(
what: &MultiAsset,
who: &MultiLocation,
what: &Asset,
who: &Location,
_maybe_context: Option<&XcmContext>,
) -> result::Result<Assets, XcmError> {
) -> result::Result<AssetsInHolding, XcmError> {
log::trace!(target: "xcm::currency_adapter", "withdraw_asset what: {:?}, who: {:?}", what, who);
// Check we handle this asset.
let amount = Matcher::matches_fungible(what).ok_or(Error::AssetNotHandled)?;
@@ -224,11 +220,11 @@ impl<
}
fn internal_transfer_asset(
asset: &MultiAsset,
from: &MultiLocation,
to: &MultiLocation,
asset: &Asset,
from: &Location,
to: &Location,
_context: &XcmContext,
) -> result::Result<Assets, XcmError> {
) -> result::Result<AssetsInHolding, XcmError> {
log::trace!(target: "xcm::currency_adapter", "internal_transfer_asset asset: {:?}, from: {:?}, to: {:?}", asset, from, to);
let amount = Matcher::matches_fungible(asset).ok_or(Error::AssetNotHandled)?;
let from =
+11 -20
View File
@@ -25,27 +25,22 @@ pub trait HandleFee {
/// fees.
///
/// Returns any part of the fee that wasn't consumed.
fn handle_fee(fee: MultiAssets, context: Option<&XcmContext>, reason: FeeReason)
-> MultiAssets;
fn handle_fee(fee: Assets, context: Option<&XcmContext>, reason: FeeReason) -> Assets;
}
// Default `HandleFee` implementation that just burns the fee.
impl HandleFee for () {
fn handle_fee(_: MultiAssets, _: Option<&XcmContext>, _: FeeReason) -> MultiAssets {
MultiAssets::new()
fn handle_fee(_: Assets, _: Option<&XcmContext>, _: FeeReason) -> Assets {
Assets::new()
}
}
#[impl_trait_for_tuples::impl_for_tuples(1, 30)]
impl HandleFee for Tuple {
fn handle_fee(
fee: MultiAssets,
context: Option<&XcmContext>,
reason: FeeReason,
) -> MultiAssets {
fn handle_fee(fee: Assets, context: Option<&XcmContext>, reason: FeeReason) -> Assets {
let mut unconsumed_fee = fee;
for_tuples!( #(
unconsumed_fee = Tuple::handle_fee(unconsumed_fee, context, reason);
unconsumed_fee = Tuple::handle_fee(unconsumed_fee, context, reason.clone());
if unconsumed_fee.is_none() {
return unconsumed_fee;
}
@@ -60,15 +55,15 @@ impl HandleFee for Tuple {
pub struct XcmFeeManagerFromComponents<WaivedLocations, HandleFee>(
PhantomData<(WaivedLocations, HandleFee)>,
);
impl<WaivedLocations: Contains<MultiLocation>, FeeHandler: HandleFee> FeeManager
impl<WaivedLocations: Contains<Location>, FeeHandler: HandleFee> FeeManager
for XcmFeeManagerFromComponents<WaivedLocations, FeeHandler>
{
fn is_waived(origin: Option<&MultiLocation>, _: FeeReason) -> bool {
fn is_waived(origin: Option<&Location>, _: FeeReason) -> bool {
let Some(loc) = origin else { return false };
WaivedLocations::contains(loc)
}
fn handle_fee(fee: MultiAssets, context: Option<&XcmContext>, reason: FeeReason) {
fn handle_fee(fee: Assets, context: Option<&XcmContext>, reason: FeeReason) {
FeeHandler::handle_fee(fee, context, reason);
}
}
@@ -76,7 +71,7 @@ impl<WaivedLocations: Contains<MultiLocation>, FeeHandler: HandleFee> FeeManager
/// Try to deposit the given fee in the specified account.
/// Burns the fee in case of a failure.
pub fn deposit_or_burn_fee<AssetTransactor: TransactAsset, AccountId: Clone + Into<[u8; 32]>>(
fee: MultiAssets,
fee: Assets,
context: Option<&XcmContext>,
receiver: AccountId,
) {
@@ -109,13 +104,9 @@ impl<
ReceiverAccount: Get<AccountId>,
> HandleFee for XcmFeeToAccount<AssetTransactor, AccountId, ReceiverAccount>
{
fn handle_fee(
fee: MultiAssets,
context: Option<&XcmContext>,
_reason: FeeReason,
) -> MultiAssets {
fn handle_fee(fee: Assets, context: Option<&XcmContext>, _reason: FeeReason) -> Assets {
deposit_or_burn_fee::<AssetTransactor, _>(fee, context, ReceiverAccount::get());
MultiAssets::new()
Assets::new()
}
}
@@ -14,28 +14,26 @@
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Various implementations of `ContainsPair<MultiAsset, MultiLocation>` or
//! `Contains<(MultiLocation, Vec<MultiAsset>)>`.
//! Various implementations of `ContainsPair<Asset, Location>` or
//! `Contains<(Location, Vec<Asset>)>`.
use frame_support::traits::{Contains, ContainsPair, Get};
use sp_std::{marker::PhantomData, vec::Vec};
use xcm::latest::{AssetId::Concrete, MultiAsset, MultiAssetFilter, MultiLocation, WildMultiAsset};
use xcm::latest::{Asset, AssetFilter, AssetId, Location, WildAsset};
/// Accepts an asset iff it is a native asset.
pub struct NativeAsset;
impl ContainsPair<MultiAsset, MultiLocation> for NativeAsset {
fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool {
impl ContainsPair<Asset, Location> for NativeAsset {
fn contains(asset: &Asset, origin: &Location) -> bool {
log::trace!(target: "xcm::contains", "NativeAsset asset: {:?}, origin: {:?}", asset, origin);
matches!(asset.id, Concrete(ref id) if id == origin)
matches!(asset.id, AssetId(ref id) if id == origin)
}
}
/// Accepts an asset if it is contained in the given `T`'s `Get` implementation.
pub struct Case<T>(PhantomData<T>);
impl<T: Get<(MultiAssetFilter, MultiLocation)>> ContainsPair<MultiAsset, MultiLocation>
for Case<T>
{
fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool {
impl<T: Get<(AssetFilter, Location)>> ContainsPair<Asset, Location> for Case<T> {
fn contains(asset: &Asset, origin: &Location) -> bool {
log::trace!(target: "xcm::contains", "Case asset: {:?}, origin: {:?}", asset, origin);
let (a, o) = T::get();
a.matches(asset) && &o == origin
@@ -44,18 +42,18 @@ impl<T: Get<(MultiAssetFilter, MultiLocation)>> ContainsPair<MultiAsset, MultiLo
/// Accepts a tuple `(location, assets)` if the `location` is contained in the `Contains`
/// implementation of the given `Location` and if every asset from `assets` matches at least one of
/// the `MultiAssetFilter` instances provided by the `Get` implementation of `AssetFilters`.
pub struct LocationWithAssetFilters<Location, AssetFilters>(
sp_std::marker::PhantomData<(Location, AssetFilters)>,
/// the `AssetFilter` instances provided by the `Get` implementation of `AssetFilters`.
pub struct LocationWithAssetFilters<LocationFilter, AssetFilters>(
sp_std::marker::PhantomData<(LocationFilter, AssetFilters)>,
);
impl<Location: Contains<MultiLocation>, AssetFilters: Get<Vec<MultiAssetFilter>>>
Contains<(MultiLocation, Vec<MultiAsset>)> for LocationWithAssetFilters<Location, AssetFilters>
impl<LocationFilter: Contains<Location>, AssetFilters: Get<Vec<AssetFilter>>>
Contains<(Location, Vec<Asset>)> for LocationWithAssetFilters<LocationFilter, AssetFilters>
{
fn contains((location, assets): &(MultiLocation, Vec<MultiAsset>)) -> bool {
fn contains((location, assets): &(Location, Vec<Asset>)) -> bool {
log::trace!(target: "xcm::contains", "LocationWithAssetFilters location: {:?}, assets: {:?}", location, assets);
// `location` must match the `Location` filter.
if !Location::contains(location) {
if !LocationFilter::contains(location) {
return false
}
@@ -72,12 +70,12 @@ impl<Location: Contains<MultiLocation>, AssetFilters: Get<Vec<MultiAssetFilter>>
}
}
/// Implementation of `Get<Vec<MultiAssetFilter>>` which accepts every asset.
/// Implementation of `Get<Vec<AssetFilter>>` which accepts every asset.
/// (For example, it can be used with `LocationWithAssetFilters`).
pub struct AllAssets;
impl Get<Vec<MultiAssetFilter>> for AllAssets {
fn get() -> Vec<MultiAssetFilter> {
sp_std::vec![MultiAssetFilter::Wild(WildMultiAsset::All)]
impl Get<Vec<AssetFilter>> for AllAssets {
fn get() -> Vec<AssetFilter> {
sp_std::vec![AssetFilter::Wild(WildAsset::All)]
}
}
@@ -90,24 +88,24 @@ mod tests {
#[test]
fn location_with_asset_filters_works() {
frame_support::parameter_types! {
pub ParaA: MultiLocation = MultiLocation::new(1, X1(Parachain(1001)));
pub ParaB: MultiLocation = MultiLocation::new(1, X1(Parachain(1002)));
pub ParaC: MultiLocation = MultiLocation::new(1, X1(Parachain(1003)));
pub ParaA: Location = Location::new(1, [Parachain(1001)]);
pub ParaB: Location = Location::new(1, [Parachain(1002)]);
pub ParaC: Location = Location::new(1, [Parachain(1003)]);
pub AssetXLocation: MultiLocation = MultiLocation::new(1, X1(GeneralIndex(1111)));
pub AssetYLocation: MultiLocation = MultiLocation::new(1, X1(GeneralIndex(2222)));
pub AssetZLocation: MultiLocation = MultiLocation::new(1, X1(GeneralIndex(3333)));
pub AssetXLocation: Location = Location::new(1, [GeneralIndex(1111)]);
pub AssetYLocation: Location = Location::new(1, [GeneralIndex(2222)]);
pub AssetZLocation: Location = Location::new(1, [GeneralIndex(3333)]);
pub OnlyAssetXOrAssetY: sp_std::vec::Vec<MultiAssetFilter> = sp_std::vec![
Wild(AllOf { fun: WildFungible, id: Concrete(AssetXLocation::get()) }),
Wild(AllOf { fun: WildFungible, id: Concrete(AssetYLocation::get()) }),
pub OnlyAssetXOrAssetY: sp_std::vec::Vec<AssetFilter> = sp_std::vec![
Wild(AllOf { fun: WildFungible, id: AssetId(AssetXLocation::get()) }),
Wild(AllOf { fun: WildFungible, id: AssetId(AssetYLocation::get()) }),
];
pub OnlyAssetZ: sp_std::vec::Vec<MultiAssetFilter> = sp_std::vec![
Wild(AllOf { fun: WildFungible, id: Concrete(AssetZLocation::get()) })
pub OnlyAssetZ: sp_std::vec::Vec<AssetFilter> = sp_std::vec![
Wild(AllOf { fun: WildFungible, id: AssetId(AssetZLocation::get()) })
];
}
let test_data: Vec<(MultiLocation, Vec<MultiAsset>, bool)> = vec![
let test_data: Vec<(Location, Vec<Asset>, bool)> = vec![
(ParaA::get(), vec![(AssetXLocation::get(), 1).into()], true),
(ParaA::get(), vec![(AssetYLocation::get(), 1).into()], true),
(ParaA::get(), vec![(AssetZLocation::get(), 1).into()], false),
@@ -202,7 +200,7 @@ mod tests {
for (location, assets, expected_result) in test_data {
assert_eq!(
Filter::contains(&(location, assets.clone())),
Filter::contains(&(location.clone(), assets.clone())),
expected_result,
"expected_result: {expected_result} not matched for (location, assets): ({:?}, {:?})!", location, assets,
)
@@ -25,7 +25,10 @@ use frame_support::traits::{
};
use sp_std::{marker::PhantomData, prelude::*, result};
use xcm::latest::prelude::*;
use xcm_executor::traits::{ConvertLocation, Error as MatchError, MatchesFungible, TransactAsset};
use xcm_executor::{
traits::{ConvertLocation, Error as MatchError, MatchesFungible, TransactAsset},
AssetsInHolding,
};
/// [`TransactAsset`] implementation that allows the use of a [`fungible`] implementation for
/// handling an asset in the XCM executor.
@@ -41,11 +44,11 @@ impl<
> TransactAsset for FungibleTransferAdapter<Fungible, Matcher, AccountIdConverter, AccountId>
{
fn internal_transfer_asset(
what: &MultiAsset,
from: &MultiLocation,
to: &MultiLocation,
what: &Asset,
from: &Location,
to: &Location,
_context: &XcmContext,
) -> result::Result<xcm_executor::Assets, XcmError> {
) -> result::Result<AssetsInHolding, XcmError> {
log::trace!(
target: "xcm::fungible_adapter",
"internal_transfer_asset what: {:?}, from: {:?}, to: {:?}",
@@ -111,11 +114,7 @@ impl<
> TransactAsset
for FungibleMutateAdapter<Fungible, Matcher, AccountIdConverter, AccountId, CheckingAccount>
{
fn can_check_in(
_origin: &MultiLocation,
what: &MultiAsset,
_context: &XcmContext,
) -> XcmResult {
fn can_check_in(_origin: &Location, what: &Asset, _context: &XcmContext) -> XcmResult {
log::trace!(
target: "xcm::fungible_adapter",
"can_check_in origin: {:?}, what: {:?}",
@@ -132,7 +131,7 @@ impl<
}
}
fn check_in(_origin: &MultiLocation, what: &MultiAsset, _context: &XcmContext) {
fn check_in(_origin: &Location, what: &Asset, _context: &XcmContext) {
log::trace!(
target: "xcm::fungible_adapter",
"check_in origin: {:?}, what: {:?}",
@@ -149,7 +148,7 @@ impl<
}
}
fn can_check_out(_dest: &MultiLocation, what: &MultiAsset, _context: &XcmContext) -> XcmResult {
fn can_check_out(_dest: &Location, what: &Asset, _context: &XcmContext) -> XcmResult {
log::trace!(
target: "xcm::fungible_adapter",
"check_out dest: {:?}, what: {:?}",
@@ -166,7 +165,7 @@ impl<
}
}
fn check_out(_dest: &MultiLocation, what: &MultiAsset, _context: &XcmContext) {
fn check_out(_dest: &Location, what: &Asset, _context: &XcmContext) {
log::trace!(
target: "xcm::fungible_adapter",
"check_out dest: {:?}, what: {:?}",
@@ -184,11 +183,7 @@ impl<
}
}
fn deposit_asset(
what: &MultiAsset,
who: &MultiLocation,
_context: Option<&XcmContext>,
) -> XcmResult {
fn deposit_asset(what: &Asset, who: &Location, _context: Option<&XcmContext>) -> XcmResult {
log::trace!(
target: "xcm::fungible_adapter",
"deposit_asset what: {:?}, who: {:?}",
@@ -203,10 +198,10 @@ impl<
}
fn withdraw_asset(
what: &MultiAsset,
who: &MultiLocation,
what: &Asset,
who: &Location,
_context: Option<&XcmContext>,
) -> result::Result<xcm_executor::Assets, XcmError> {
) -> result::Result<AssetsInHolding, XcmError> {
log::trace!(
target: "xcm::fungible_adapter",
"deposit_asset what: {:?}, who: {:?}",
@@ -236,7 +231,7 @@ impl<
> TransactAsset
for FungibleAdapter<Fungible, Matcher, AccountIdConverter, AccountId, CheckingAccount>
{
fn can_check_in(origin: &MultiLocation, what: &MultiAsset, context: &XcmContext) -> XcmResult {
fn can_check_in(origin: &Location, what: &Asset, context: &XcmContext) -> XcmResult {
FungibleMutateAdapter::<
Fungible,
Matcher,
@@ -246,7 +241,7 @@ impl<
>::can_check_in(origin, what, context)
}
fn check_in(origin: &MultiLocation, what: &MultiAsset, context: &XcmContext) {
fn check_in(origin: &Location, what: &Asset, context: &XcmContext) {
FungibleMutateAdapter::<
Fungible,
Matcher,
@@ -256,7 +251,7 @@ impl<
>::check_in(origin, what, context)
}
fn can_check_out(dest: &MultiLocation, what: &MultiAsset, context: &XcmContext) -> XcmResult {
fn can_check_out(dest: &Location, what: &Asset, context: &XcmContext) -> XcmResult {
FungibleMutateAdapter::<
Fungible,
Matcher,
@@ -266,7 +261,7 @@ impl<
>::can_check_out(dest, what, context)
}
fn check_out(dest: &MultiLocation, what: &MultiAsset, context: &XcmContext) {
fn check_out(dest: &Location, what: &Asset, context: &XcmContext) {
FungibleMutateAdapter::<
Fungible,
Matcher,
@@ -276,11 +271,7 @@ impl<
>::check_out(dest, what, context)
}
fn deposit_asset(
what: &MultiAsset,
who: &MultiLocation,
context: Option<&XcmContext>,
) -> XcmResult {
fn deposit_asset(what: &Asset, who: &Location, context: Option<&XcmContext>) -> XcmResult {
FungibleMutateAdapter::<
Fungible,
Matcher,
@@ -291,10 +282,10 @@ impl<
}
fn withdraw_asset(
what: &MultiAsset,
who: &MultiLocation,
what: &Asset,
who: &Location,
maybe_context: Option<&XcmContext>,
) -> result::Result<xcm_executor::Assets, XcmError> {
) -> result::Result<AssetsInHolding, XcmError> {
FungibleMutateAdapter::<
Fungible,
Matcher,
@@ -305,11 +296,11 @@ impl<
}
fn internal_transfer_asset(
what: &MultiAsset,
from: &MultiLocation,
to: &MultiLocation,
what: &Asset,
from: &Location,
to: &Location,
context: &XcmContext,
) -> result::Result<xcm_executor::Assets, XcmError> {
) -> result::Result<AssetsInHolding, XcmError> {
FungibleTransferAdapter::<Fungible, Matcher, AccountIdConverter, AccountId>::internal_transfer_asset(
what, from, to, context
)
@@ -38,11 +38,11 @@ impl<
> TransactAsset for FungiblesTransferAdapter<Assets, Matcher, AccountIdConverter, AccountId>
{
fn internal_transfer_asset(
what: &MultiAsset,
from: &MultiLocation,
to: &MultiLocation,
what: &Asset,
from: &Location,
to: &Location,
_context: &XcmContext,
) -> result::Result<xcm_executor::Assets, XcmError> {
) -> result::Result<xcm_executor::AssetsInHolding, XcmError> {
log::trace!(
target: "xcm::fungibles_adapter",
"internal_transfer_asset what: {:?}, from: {:?}, to: {:?}",
@@ -198,11 +198,7 @@ impl<
CheckingAccount,
>
{
fn can_check_in(
_origin: &MultiLocation,
what: &MultiAsset,
_context: &XcmContext,
) -> XcmResult {
fn can_check_in(_origin: &Location, what: &Asset, _context: &XcmContext) -> XcmResult {
log::trace!(
target: "xcm::fungibles_adapter",
"can_check_in origin: {:?}, what: {:?}",
@@ -219,7 +215,7 @@ impl<
}
}
fn check_in(_origin: &MultiLocation, what: &MultiAsset, _context: &XcmContext) {
fn check_in(_origin: &Location, what: &Asset, _context: &XcmContext) {
log::trace!(
target: "xcm::fungibles_adapter",
"check_in origin: {:?}, what: {:?}",
@@ -236,11 +232,7 @@ impl<
}
}
fn can_check_out(
_origin: &MultiLocation,
what: &MultiAsset,
_context: &XcmContext,
) -> XcmResult {
fn can_check_out(_origin: &Location, what: &Asset, _context: &XcmContext) -> XcmResult {
log::trace!(
target: "xcm::fungibles_adapter",
"can_check_in origin: {:?}, what: {:?}",
@@ -257,7 +249,7 @@ impl<
}
}
fn check_out(_dest: &MultiLocation, what: &MultiAsset, _context: &XcmContext) {
fn check_out(_dest: &Location, what: &Asset, _context: &XcmContext) {
log::trace!(
target: "xcm::fungibles_adapter",
"check_out dest: {:?}, what: {:?}",
@@ -274,11 +266,7 @@ impl<
}
}
fn deposit_asset(
what: &MultiAsset,
who: &MultiLocation,
_context: Option<&XcmContext>,
) -> XcmResult {
fn deposit_asset(what: &Asset, who: &Location, _context: Option<&XcmContext>) -> XcmResult {
log::trace!(
target: "xcm::fungibles_adapter",
"deposit_asset what: {:?}, who: {:?}",
@@ -294,10 +282,10 @@ impl<
}
fn withdraw_asset(
what: &MultiAsset,
who: &MultiLocation,
what: &Asset,
who: &Location,
_maybe_context: Option<&XcmContext>,
) -> result::Result<xcm_executor::Assets, XcmError> {
) -> result::Result<xcm_executor::AssetsInHolding, XcmError> {
log::trace!(
target: "xcm::fungibles_adapter",
"withdraw_asset what: {:?}, who: {:?}",
@@ -331,7 +319,7 @@ impl<
> TransactAsset
for FungiblesAdapter<Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount>
{
fn can_check_in(origin: &MultiLocation, what: &MultiAsset, context: &XcmContext) -> XcmResult {
fn can_check_in(origin: &Location, what: &Asset, context: &XcmContext) -> XcmResult {
FungiblesMutateAdapter::<
Assets,
Matcher,
@@ -342,7 +330,7 @@ impl<
>::can_check_in(origin, what, context)
}
fn check_in(origin: &MultiLocation, what: &MultiAsset, context: &XcmContext) {
fn check_in(origin: &Location, what: &Asset, context: &XcmContext) {
FungiblesMutateAdapter::<
Assets,
Matcher,
@@ -353,7 +341,7 @@ impl<
>::check_in(origin, what, context)
}
fn can_check_out(dest: &MultiLocation, what: &MultiAsset, context: &XcmContext) -> XcmResult {
fn can_check_out(dest: &Location, what: &Asset, context: &XcmContext) -> XcmResult {
FungiblesMutateAdapter::<
Assets,
Matcher,
@@ -364,7 +352,7 @@ impl<
>::can_check_out(dest, what, context)
}
fn check_out(dest: &MultiLocation, what: &MultiAsset, context: &XcmContext) {
fn check_out(dest: &Location, what: &Asset, context: &XcmContext) {
FungiblesMutateAdapter::<
Assets,
Matcher,
@@ -375,11 +363,7 @@ impl<
>::check_out(dest, what, context)
}
fn deposit_asset(
what: &MultiAsset,
who: &MultiLocation,
context: Option<&XcmContext>,
) -> XcmResult {
fn deposit_asset(what: &Asset, who: &Location, context: Option<&XcmContext>) -> XcmResult {
FungiblesMutateAdapter::<
Assets,
Matcher,
@@ -391,10 +375,10 @@ impl<
}
fn withdraw_asset(
what: &MultiAsset,
who: &MultiLocation,
what: &Asset,
who: &Location,
maybe_context: Option<&XcmContext>,
) -> result::Result<xcm_executor::Assets, XcmError> {
) -> result::Result<xcm_executor::AssetsInHolding, XcmError> {
FungiblesMutateAdapter::<
Assets,
Matcher,
@@ -406,11 +390,11 @@ impl<
}
fn internal_transfer_asset(
what: &MultiAsset,
from: &MultiLocation,
to: &MultiLocation,
what: &Asset,
from: &Location,
to: &Location,
context: &XcmContext,
) -> result::Result<xcm_executor::Assets, XcmError> {
) -> result::Result<xcm_executor::AssetsInHolding, XcmError> {
FungiblesTransferAdapter::<Assets, Matcher, AccountIdConverter, AccountId>::internal_transfer_asset(
what, from, to, context
)
+5 -5
View File
@@ -47,11 +47,11 @@ pub use origin_conversion::{
};
mod asset_conversion;
pub use asset_conversion::{
AsPrefixedGeneralIndex, ConvertedAbstractId, ConvertedConcreteId, MatchedConvertedConcreteId,
};
#[allow(deprecated)]
pub use asset_conversion::{ConvertedAbstractAssetId, ConvertedConcreteAssetId};
pub use asset_conversion::ConvertedConcreteAssetId;
pub use asset_conversion::{
AsPrefixedGeneralIndex, ConvertedConcreteId, MatchedConvertedConcreteId, V4V3LocationConverter,
};
mod barriers;
pub use barriers::{
@@ -96,7 +96,7 @@ mod matches_location;
pub use matches_location::{StartsWith, StartsWithExplicitGlobalConsensus};
mod matches_token;
pub use matches_token::{IsAbstract, IsConcrete};
pub use matches_token::IsConcrete;
mod matcher;
pub use matcher::{CreateMatcher, MatchXcm, Matcher};
@@ -27,12 +27,12 @@ use xcm_executor::traits::ConvertLocation;
pub trait DescribeLocation {
/// Create a description of the given `location` if possible. No two locations should have the
/// same descriptor.
fn describe_location(location: &MultiLocation) -> Option<Vec<u8>>;
fn describe_location(location: &Location) -> Option<Vec<u8>>;
}
#[impl_trait_for_tuples::impl_for_tuples(30)]
impl DescribeLocation for Tuple {
fn describe_location(l: &MultiLocation) -> Option<Vec<u8>> {
fn describe_location(l: &Location) -> Option<Vec<u8>> {
for_tuples!( #(
match Tuple::describe_location(l) {
Some(result) => return Some(result),
@@ -45,9 +45,9 @@ impl DescribeLocation for Tuple {
pub struct DescribeTerminus;
impl DescribeLocation for DescribeTerminus {
fn describe_location(l: &MultiLocation) -> Option<Vec<u8>> {
match (l.parents, &l.interior) {
(0, Here) => Some(Vec::new()),
fn describe_location(l: &Location) -> Option<Vec<u8>> {
match l.unpack() {
(0, []) => Some(Vec::new()),
_ => return None,
}
}
@@ -55,10 +55,9 @@ impl DescribeLocation for DescribeTerminus {
pub struct DescribePalletTerminal;
impl DescribeLocation for DescribePalletTerminal {
fn describe_location(l: &MultiLocation) -> Option<Vec<u8>> {
match (l.parents, &l.interior) {
(0, X1(PalletInstance(i))) =>
Some((b"Pallet", Compact::<u32>::from(*i as u32)).encode()),
fn describe_location(l: &Location) -> Option<Vec<u8>> {
match l.unpack() {
(0, [PalletInstance(i)]) => Some((b"Pallet", Compact::<u32>::from(*i as u32)).encode()),
_ => return None,
}
}
@@ -66,9 +65,9 @@ impl DescribeLocation for DescribePalletTerminal {
pub struct DescribeAccountId32Terminal;
impl DescribeLocation for DescribeAccountId32Terminal {
fn describe_location(l: &MultiLocation) -> Option<Vec<u8>> {
match (l.parents, &l.interior) {
(0, X1(AccountId32 { id, .. })) => Some((b"AccountId32", id).encode()),
fn describe_location(l: &Location) -> Option<Vec<u8>> {
match l.unpack() {
(0, [AccountId32 { id, .. }]) => Some((b"AccountId32", id).encode()),
_ => return None,
}
}
@@ -76,9 +75,9 @@ impl DescribeLocation for DescribeAccountId32Terminal {
pub struct DescribeAccountKey20Terminal;
impl DescribeLocation for DescribeAccountKey20Terminal {
fn describe_location(l: &MultiLocation) -> Option<Vec<u8>> {
match (l.parents, &l.interior) {
(0, X1(AccountKey20 { key, .. })) => Some((b"AccountKey20", key).encode()),
fn describe_location(l: &Location) -> Option<Vec<u8>> {
match l.unpack() {
(0, [AccountKey20 { key, .. }]) => Some((b"AccountKey20", key).encode()),
_ => return None,
}
}
@@ -89,9 +88,9 @@ impl DescribeLocation for DescribeAccountKey20Terminal {
pub struct DescribeTreasuryVoiceTerminal;
impl DescribeLocation for DescribeTreasuryVoiceTerminal {
fn describe_location(l: &MultiLocation) -> Option<Vec<u8>> {
match (l.parents, &l.interior) {
(0, X1(Plurality { id: BodyId::Treasury, part: BodyPart::Voice })) =>
fn describe_location(location: &Location) -> Option<Vec<u8>> {
match location.unpack() {
(0, [Plurality { id: BodyId::Treasury, part: BodyPart::Voice }]) =>
Some((b"Treasury", b"Voice").encode()),
_ => None,
}
@@ -102,9 +101,9 @@ pub type DescribeAccountIdTerminal = (DescribeAccountId32Terminal, DescribeAccou
pub struct DescribeBodyTerminal;
impl DescribeLocation for DescribeBodyTerminal {
fn describe_location(l: &MultiLocation) -> Option<Vec<u8>> {
match (l.parents, &l.interior) {
(0, X1(Plurality { id, part })) => Some((b"Body", id, part).encode()),
fn describe_location(l: &Location) -> Option<Vec<u8>> {
match l.unpack() {
(0, [Plurality { id, part }]) => Some((b"Body", id, part).encode()),
_ => return None,
}
}
@@ -121,20 +120,21 @@ pub type DescribeAllTerminal = (
pub struct DescribeFamily<DescribeInterior>(PhantomData<DescribeInterior>);
impl<Suffix: DescribeLocation> DescribeLocation for DescribeFamily<Suffix> {
fn describe_location(l: &MultiLocation) -> Option<Vec<u8>> {
match (l.parents, l.interior.first()) {
fn describe_location(l: &Location) -> Option<Vec<u8>> {
match (l.parent_count(), l.first_interior()) {
(0, Some(Parachain(index))) => {
let tail = l.interior.split_first().0;
let tail = l.clone().split_first_interior().0;
let interior = Suffix::describe_location(&tail.into())?;
Some((b"ChildChain", Compact::<u32>::from(*index), interior).encode())
},
(1, Some(Parachain(index))) => {
let tail = l.interior.split_first().0;
let interior = Suffix::describe_location(&tail.into())?;
let tail_junctions = l.interior().clone().split_first().0;
let tail = Location::new(0, tail_junctions);
let interior = Suffix::describe_location(&tail)?;
Some((b"SiblingChain", Compact::<u32>::from(*index), interior).encode())
},
(1, _) => {
let tail = l.interior.into();
let tail = l.interior().clone().into();
let interior = Suffix::describe_location(&tail)?;
Some((b"ParentChain", interior).encode())
},
@@ -147,7 +147,7 @@ pub struct HashedDescription<AccountId, Describe>(PhantomData<(AccountId, Descri
impl<AccountId: From<[u8; 32]> + Clone, Describe: DescribeLocation> ConvertLocation<AccountId>
for HashedDescription<AccountId, Describe>
{
fn convert_location(value: &MultiLocation) -> Option<AccountId> {
fn convert_location(value: &Location) -> Option<AccountId> {
Some(blake2_256(&Describe::describe_location(value)?).into())
}
}
@@ -156,34 +156,26 @@ impl<AccountId: From<[u8; 32]> + Clone, Describe: DescribeLocation> ConvertLocat
/// are recommended to use the more extensible `HashedDescription` type.
pub struct LegacyDescribeForeignChainAccount;
impl DescribeLocation for LegacyDescribeForeignChainAccount {
fn describe_location(location: &MultiLocation) -> Option<Vec<u8>> {
Some(match location {
fn describe_location(location: &Location) -> Option<Vec<u8>> {
Some(match location.unpack() {
// Used on the relay chain for sending paras that use 32 byte accounts
MultiLocation {
parents: 0,
interior: X2(Parachain(para_id), AccountId32 { id, .. }),
} => LegacyDescribeForeignChainAccount::from_para_32(para_id, id, 0),
(0, [Parachain(para_id), AccountId32 { id, .. }]) =>
LegacyDescribeForeignChainAccount::from_para_32(para_id, id, 0),
// Used on the relay chain for sending paras that use 20 byte accounts
MultiLocation {
parents: 0,
interior: X2(Parachain(para_id), AccountKey20 { key, .. }),
} => LegacyDescribeForeignChainAccount::from_para_20(para_id, key, 0),
(0, [Parachain(para_id), AccountKey20 { key, .. }]) =>
LegacyDescribeForeignChainAccount::from_para_20(para_id, key, 0),
// Used on para-chain for sending paras that use 32 byte accounts
MultiLocation {
parents: 1,
interior: X2(Parachain(para_id), AccountId32 { id, .. }),
} => LegacyDescribeForeignChainAccount::from_para_32(para_id, id, 1),
(1, [Parachain(para_id), AccountId32 { id, .. }]) =>
LegacyDescribeForeignChainAccount::from_para_32(para_id, id, 1),
// Used on para-chain for sending paras that use 20 byte accounts
MultiLocation {
parents: 1,
interior: X2(Parachain(para_id), AccountKey20 { key, .. }),
} => LegacyDescribeForeignChainAccount::from_para_20(para_id, key, 1),
(1, [Parachain(para_id), AccountKey20 { key, .. }]) =>
LegacyDescribeForeignChainAccount::from_para_20(para_id, key, 1),
// Used on para-chain for sending from the relay chain
MultiLocation { parents: 1, interior: X1(AccountId32 { id, .. }) } =>
(1, [AccountId32 { id, .. }]) =>
LegacyDescribeForeignChainAccount::from_relay_32(id, 1),
// No other conversions provided
@@ -278,16 +270,16 @@ pub struct Account32Hash<Network, AccountId>(PhantomData<(Network, AccountId)>);
impl<Network: Get<Option<NetworkId>>, AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone>
ConvertLocation<AccountId> for Account32Hash<Network, AccountId>
{
fn convert_location(location: &MultiLocation) -> Option<AccountId> {
fn convert_location(location: &Location) -> Option<AccountId> {
Some(("multiloc", location).using_encoded(blake2_256).into())
}
}
/// A [`MultiLocation`] consisting of a single `Parent` [`Junction`] will be converted to the
/// A [`Location`] consisting of a single `Parent` [`Junction`] will be converted to the
/// parent `AccountId`.
pub struct ParentIsPreset<AccountId>(PhantomData<AccountId>);
impl<AccountId: Decode + Eq + Clone> ConvertLocation<AccountId> for ParentIsPreset<AccountId> {
fn convert_location(location: &MultiLocation) -> Option<AccountId> {
fn convert_location(location: &Location) -> Option<AccountId> {
if location.contains_parents_only(1) {
Some(
b"Parent"
@@ -304,10 +296,9 @@ pub struct ChildParachainConvertsVia<ParaId, AccountId>(PhantomData<(ParaId, Acc
impl<ParaId: From<u32> + Into<u32> + AccountIdConversion<AccountId>, AccountId: Clone>
ConvertLocation<AccountId> for ChildParachainConvertsVia<ParaId, AccountId>
{
fn convert_location(location: &MultiLocation) -> Option<AccountId> {
match location {
MultiLocation { parents: 0, interior: X1(Parachain(id)) } =>
Some(ParaId::from(*id).into_account_truncating()),
fn convert_location(location: &Location) -> Option<AccountId> {
match location.unpack() {
(0, [Parachain(id)]) => Some(ParaId::from(*id).into_account_truncating()),
_ => None,
}
}
@@ -317,10 +308,9 @@ pub struct SiblingParachainConvertsVia<ParaId, AccountId>(PhantomData<(ParaId, A
impl<ParaId: From<u32> + Into<u32> + AccountIdConversion<AccountId>, AccountId: Clone>
ConvertLocation<AccountId> for SiblingParachainConvertsVia<ParaId, AccountId>
{
fn convert_location(location: &MultiLocation) -> Option<AccountId> {
match location {
MultiLocation { parents: 1, interior: X1(Parachain(id)) } =>
Some(ParaId::from(*id).into_account_truncating()),
fn convert_location(location: &Location) -> Option<AccountId> {
match location.unpack() {
(1, [Parachain(id)]) => Some(ParaId::from(*id).into_account_truncating()),
_ => None,
}
}
@@ -331,15 +321,13 @@ pub struct AccountId32Aliases<Network, AccountId>(PhantomData<(Network, AccountI
impl<Network: Get<Option<NetworkId>>, AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone>
ConvertLocation<AccountId> for AccountId32Aliases<Network, AccountId>
{
fn convert_location(location: &MultiLocation) -> Option<AccountId> {
let id = match *location {
MultiLocation { parents: 0, interior: X1(AccountId32 { id, network: None }) } => id,
MultiLocation { parents: 0, interior: X1(AccountId32 { id, network }) }
if network == Network::get() =>
id,
fn convert_location(location: &Location) -> Option<AccountId> {
let id = match location.unpack() {
(0, [AccountId32 { id, network: None }]) => id,
(0, [AccountId32 { id, network }]) if *network == Network::get() => id,
_ => return None,
};
Some(id.into())
Some((*id).into())
}
}
@@ -351,25 +339,23 @@ pub struct LocalTreasuryVoiceConvertsVia<TreasuryAccount, AccountId>(
impl<TreasuryAccount: Get<AccountId>, AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone>
ConvertLocation<AccountId> for LocalTreasuryVoiceConvertsVia<TreasuryAccount, AccountId>
{
fn convert_location(location: &MultiLocation) -> Option<AccountId> {
match *location {
MultiLocation {
parents: 0,
interior: X1(Plurality { id: BodyId::Treasury, part: BodyPart::Voice }),
} => Some((TreasuryAccount::get().into() as [u8; 32]).into()),
fn convert_location(location: &Location) -> Option<AccountId> {
match location.unpack() {
(0, [Plurality { id: BodyId::Treasury, part: BodyPart::Voice }]) =>
Some((TreasuryAccount::get().into() as [u8; 32]).into()),
_ => None,
}
}
}
/// Conversion implementation which converts from a `[u8; 32]`-based `AccountId` into a
/// `MultiLocation` consisting solely of a `AccountId32` junction with a fixed value for its
/// `Location` consisting solely of a `AccountId32` junction with a fixed value for its
/// network (provided by `Network`) and the `AccountId`'s `[u8; 32]` datum for the `id`.
pub struct AliasesIntoAccountId32<Network, AccountId>(PhantomData<(Network, AccountId)>);
impl<'a, Network: Get<Option<NetworkId>>, AccountId: Clone + Into<[u8; 32]> + Clone>
TryConvert<&'a AccountId, MultiLocation> for AliasesIntoAccountId32<Network, AccountId>
TryConvert<&'a AccountId, Location> for AliasesIntoAccountId32<Network, AccountId>
{
fn try_convert(who: &AccountId) -> Result<MultiLocation, &AccountId> {
fn try_convert(who: &AccountId) -> Result<Location, &AccountId> {
Ok(AccountId32 { network: Network::get(), id: who.clone().into() }.into())
}
}
@@ -378,15 +364,13 @@ pub struct AccountKey20Aliases<Network, AccountId>(PhantomData<(Network, Account
impl<Network: Get<Option<NetworkId>>, AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone>
ConvertLocation<AccountId> for AccountKey20Aliases<Network, AccountId>
{
fn convert_location(location: &MultiLocation) -> Option<AccountId> {
let key = match *location {
MultiLocation { parents: 0, interior: X1(AccountKey20 { key, network: None }) } => key,
MultiLocation { parents: 0, interior: X1(AccountKey20 { key, network }) }
if network == Network::get() =>
key,
fn convert_location(location: &Location) -> Option<AccountId> {
let key = match location.unpack() {
(0, [AccountKey20 { key, network: None }]) => key,
(0, [AccountKey20 { key, network }]) if *network == Network::get() => key,
_ => return None,
};
Some(key.into())
Some((*key).into())
}
}
@@ -402,10 +386,10 @@ impl<Network: Get<Option<NetworkId>>, AccountId: From<[u8; 20]> + Into<[u8; 20]>
pub struct GlobalConsensusConvertsFor<UniversalLocation, AccountId>(
PhantomData<(UniversalLocation, AccountId)>,
);
impl<UniversalLocation: Get<InteriorMultiLocation>, AccountId: From<[u8; 32]> + Clone>
impl<UniversalLocation: Get<InteriorLocation>, AccountId: From<[u8; 32]> + Clone>
ConvertLocation<AccountId> for GlobalConsensusConvertsFor<UniversalLocation, AccountId>
{
fn convert_location(location: &MultiLocation) -> Option<AccountId> {
fn convert_location(location: &Location) -> Option<AccountId> {
let universal_source = UniversalLocation::get();
log::trace!(
target: "xcm::location_conversion",
@@ -413,7 +397,7 @@ impl<UniversalLocation: Get<InteriorMultiLocation>, AccountId: From<[u8; 32]> +
universal_source, location,
);
let (remote_network, remote_location) =
ensure_is_remote(universal_source, *location).ok()?;
ensure_is_remote(universal_source, location.clone()).ok()?;
match remote_location {
Here => Some(AccountId::from(Self::from_params(&remote_network))),
@@ -445,21 +429,21 @@ impl<UniversalLocation, AccountId> GlobalConsensusConvertsFor<UniversalLocation,
pub struct GlobalConsensusParachainConvertsFor<UniversalLocation, AccountId>(
PhantomData<(UniversalLocation, AccountId)>,
);
impl<UniversalLocation: Get<InteriorMultiLocation>, AccountId: From<[u8; 32]> + Clone>
impl<UniversalLocation: Get<InteriorLocation>, AccountId: From<[u8; 32]> + Clone>
ConvertLocation<AccountId> for GlobalConsensusParachainConvertsFor<UniversalLocation, AccountId>
{
fn convert_location(location: &MultiLocation) -> Option<AccountId> {
fn convert_location(location: &Location) -> Option<AccountId> {
let universal_source = UniversalLocation::get();
log::trace!(
target: "xcm::location_conversion",
"GlobalConsensusParachainConvertsFor universal_source: {:?}, location: {:?}",
universal_source, location,
);
let devolved = ensure_is_remote(universal_source, *location).ok()?;
let devolved = ensure_is_remote(universal_source, location.clone()).ok()?;
let (remote_network, remote_location) = devolved;
match remote_location {
X1(Parachain(remote_network_para_id)) =>
match remote_location.as_slice() {
[Parachain(remote_network_para_id)] =>
Some(AccountId::from(Self::from_params(&remote_network, &remote_network_para_id))),
_ => None,
}
@@ -509,12 +493,12 @@ mod tests {
#[test]
fn inverter_works_in_tree() {
parameter_types! {
pub UniversalLocation: InteriorMultiLocation = X3(Parachain(1), account20(), account20());
pub UniversalLocation: InteriorLocation = [Parachain(1), account20(), account20()].into();
}
let input = MultiLocation::new(3, X2(Parachain(2), account32()));
let input = Location::new(3, [Parachain(2), account32()]);
let inverted = UniversalLocation::get().invert_target(&input).unwrap();
assert_eq!(inverted, MultiLocation::new(2, X3(Parachain(1), account20(), account20())));
assert_eq!(inverted, Location::new(2, [Parachain(1), account20(), account20()]));
}
// Network Topology
@@ -524,12 +508,12 @@ mod tests {
#[test]
fn inverter_uses_context_as_inverted_location() {
parameter_types! {
pub UniversalLocation: InteriorMultiLocation = X2(account20(), account20());
pub UniversalLocation: InteriorLocation = [account20(), account20()].into();
}
let input = MultiLocation::grandparent();
let input = Location::new(2, Here);
let inverted = UniversalLocation::get().invert_target(&input).unwrap();
assert_eq!(inverted, X2(account20(), account20()).into());
assert_eq!(inverted, [account20(), account20()].into());
}
// Network Topology
@@ -539,10 +523,10 @@ mod tests {
#[test]
fn inverter_uses_only_child_on_missing_context() {
parameter_types! {
pub UniversalLocation: InteriorMultiLocation = PalletInstance(5).into();
pub UniversalLocation: InteriorLocation = PalletInstance(5).into();
}
let input = MultiLocation::grandparent();
let input = Location::new(2, Here);
let inverted = UniversalLocation::get().invert_target(&input).unwrap();
assert_eq!(inverted, (OnlyChild, PalletInstance(5)).into());
}
@@ -550,10 +534,10 @@ mod tests {
#[test]
fn inverter_errors_when_location_is_too_large() {
parameter_types! {
pub UniversalLocation: InteriorMultiLocation = Here;
pub UniversalLocation: InteriorLocation = Here;
}
let input = MultiLocation { parents: 99, interior: X1(Parachain(88)) };
let input = Location { parents: 99, interior: [Parachain(88)].into() };
let inverted = UniversalLocation::get().invert_target(&input);
assert_eq!(inverted, Err(()));
}
@@ -561,8 +545,8 @@ mod tests {
#[test]
fn global_consensus_converts_for_works() {
parameter_types! {
pub UniversalLocationInNetwork1: InteriorMultiLocation = X2(GlobalConsensus(ByGenesis([1; 32])), Parachain(1234));
pub UniversalLocationInNetwork2: InteriorMultiLocation = X2(GlobalConsensus(ByGenesis([2; 32])), Parachain(1234));
pub UniversalLocationInNetwork1: InteriorLocation = [GlobalConsensus(ByGenesis([1; 32])), Parachain(1234)].into();
pub UniversalLocationInNetwork2: InteriorLocation = [GlobalConsensus(ByGenesis([2; 32])), Parachain(1234)].into();
}
let network_1 = UniversalLocationInNetwork1::get().global_consensus().expect("NetworkId");
let network_2 = UniversalLocationInNetwork2::get().global_consensus().expect("NetworkId");
@@ -571,17 +555,17 @@ mod tests {
let network_5 = ByGenesis([5; 32]);
let test_data = vec![
(MultiLocation::parent(), false),
(MultiLocation::new(0, Here), false),
(MultiLocation::new(0, X1(GlobalConsensus(network_1))), false),
(MultiLocation::new(1, X1(GlobalConsensus(network_1))), false),
(MultiLocation::new(2, X1(GlobalConsensus(network_1))), false),
(MultiLocation::new(0, X1(GlobalConsensus(network_2))), false),
(MultiLocation::new(1, X1(GlobalConsensus(network_2))), false),
(MultiLocation::new(2, X1(GlobalConsensus(network_2))), true),
(MultiLocation::new(0, X2(GlobalConsensus(network_2), Parachain(1000))), false),
(MultiLocation::new(1, X2(GlobalConsensus(network_2), Parachain(1000))), false),
(MultiLocation::new(2, X2(GlobalConsensus(network_2), Parachain(1000))), false),
(Location::parent(), false),
(Location::new(0, Here), false),
(Location::new(0, [GlobalConsensus(network_1)]), false),
(Location::new(1, [GlobalConsensus(network_1)]), false),
(Location::new(2, [GlobalConsensus(network_1)]), false),
(Location::new(0, [GlobalConsensus(network_2)]), false),
(Location::new(1, [GlobalConsensus(network_2)]), false),
(Location::new(2, [GlobalConsensus(network_2)]), true),
(Location::new(0, [GlobalConsensus(network_2), Parachain(1000)]), false),
(Location::new(1, [GlobalConsensus(network_2), Parachain(1000)]), false),
(Location::new(2, [GlobalConsensus(network_2), Parachain(1000)]), false),
];
for (location, expected_result) in test_data {
@@ -596,14 +580,14 @@ mod tests {
"expected_result: {}, but conversion passed: {:?}, location: {:?}",
expected_result, account, location
);
match &location {
MultiLocation { interior: X1(GlobalConsensus(network)), .. } =>
match location.unpack() {
(_, [GlobalConsensus(network)]) =>
assert_eq!(
account,
GlobalConsensusConvertsFor::<UniversalLocationInNetwork1, [u8; 32]>::from_params(network),
"expected_result: {}, but conversion passed: {:?}, location: {:?}", expected_result, account, location
),
_ => panic!("expected_result: {}, conversion passed: {:?}, but MultiLocation does not match expected pattern, location: {:?}", expected_result, account, location)
_ => panic!("expected_result: {}, conversion passed: {:?}, but Location does not match expected pattern, location: {:?}", expected_result, account, location)
}
},
None => {
@@ -619,32 +603,32 @@ mod tests {
// all success
let res_1_gc_network_3 =
GlobalConsensusConvertsFor::<UniversalLocationInNetwork1, [u8; 32]>::convert_location(
&MultiLocation::new(2, X1(GlobalConsensus(network_3))),
&Location::new(2, [GlobalConsensus(network_3)]),
)
.expect("conversion is ok");
let res_2_gc_network_3 =
GlobalConsensusConvertsFor::<UniversalLocationInNetwork2, [u8; 32]>::convert_location(
&MultiLocation::new(2, X1(GlobalConsensus(network_3))),
&Location::new(2, [GlobalConsensus(network_3)]),
)
.expect("conversion is ok");
let res_1_gc_network_4 =
GlobalConsensusConvertsFor::<UniversalLocationInNetwork1, [u8; 32]>::convert_location(
&MultiLocation::new(2, X1(GlobalConsensus(network_4))),
&Location::new(2, [GlobalConsensus(network_4)]),
)
.expect("conversion is ok");
let res_2_gc_network_4 =
GlobalConsensusConvertsFor::<UniversalLocationInNetwork2, [u8; 32]>::convert_location(
&MultiLocation::new(2, X1(GlobalConsensus(network_4))),
&Location::new(2, [GlobalConsensus(network_4)]),
)
.expect("conversion is ok");
let res_1_gc_network_5 =
GlobalConsensusConvertsFor::<UniversalLocationInNetwork1, [u8; 32]>::convert_location(
&MultiLocation::new(2, X1(GlobalConsensus(network_5))),
&Location::new(2, [GlobalConsensus(network_5)]),
)
.expect("conversion is ok");
let res_2_gc_network_5 =
GlobalConsensusConvertsFor::<UniversalLocationInNetwork2, [u8; 32]>::convert_location(
&MultiLocation::new(2, X1(GlobalConsensus(network_5))),
&Location::new(2, [GlobalConsensus(network_5)]),
)
.expect("conversion is ok");
@@ -660,42 +644,30 @@ mod tests {
#[test]
fn global_consensus_parachain_converts_for_works() {
parameter_types! {
pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(ByGenesis([9; 32])), Parachain(1234));
pub UniversalLocation: InteriorLocation = [GlobalConsensus(ByGenesis([9; 32])), Parachain(1234)].into();
}
let test_data = vec![
(MultiLocation::parent(), false),
(MultiLocation::new(0, X1(Parachain(1000))), false),
(MultiLocation::new(1, X1(Parachain(1000))), false),
(Location::parent(), false),
(Location::new(0, [Parachain(1000)]), false),
(Location::new(1, [Parachain(1000)]), false),
(
MultiLocation::new(
Location::new(
2,
X3(
[
GlobalConsensus(ByGenesis([0; 32])),
Parachain(1000),
AccountId32 { network: None, id: [1; 32].into() },
),
],
),
false,
),
(MultiLocation::new(2, X1(GlobalConsensus(ByGenesis([0; 32])))), false),
(
MultiLocation::new(0, X2(GlobalConsensus(ByGenesis([0; 32])), Parachain(1000))),
false,
),
(
MultiLocation::new(1, X2(GlobalConsensus(ByGenesis([0; 32])), Parachain(1000))),
false,
),
(MultiLocation::new(2, X2(GlobalConsensus(ByGenesis([0; 32])), Parachain(1000))), true),
(
MultiLocation::new(3, X2(GlobalConsensus(ByGenesis([0; 32])), Parachain(1000))),
false,
),
(
MultiLocation::new(9, X2(GlobalConsensus(ByGenesis([0; 32])), Parachain(1000))),
false,
),
(Location::new(2, [GlobalConsensus(ByGenesis([0; 32]))]), false),
(Location::new(0, [GlobalConsensus(ByGenesis([0; 32])), Parachain(1000)]), false),
(Location::new(1, [GlobalConsensus(ByGenesis([0; 32])), Parachain(1000)]), false),
(Location::new(2, [GlobalConsensus(ByGenesis([0; 32])), Parachain(1000)]), true),
(Location::new(3, [GlobalConsensus(ByGenesis([0; 32])), Parachain(1000)]), false),
(Location::new(9, [GlobalConsensus(ByGenesis([0; 32])), Parachain(1000)]), false),
];
for (location, expected_result) in test_data {
@@ -710,8 +682,8 @@ mod tests {
"expected_result: {}, but conversion passed: {:?}, location: {:?}",
expected_result, account, location
);
match &location {
MultiLocation { interior: X2(GlobalConsensus(network), Parachain(para_id)), .. } =>
match location.unpack() {
(_, [GlobalConsensus(network), Parachain(para_id)]) =>
assert_eq!(
account,
GlobalConsensusParachainConvertsFor::<UniversalLocation, [u8; 32]>::from_params(network, para_id),
@@ -720,7 +692,7 @@ mod tests {
_ => assert_eq!(
true,
expected_result,
"expected_result: {}, conversion passed: {:?}, but MultiLocation does not match expected pattern, location: {:?}", expected_result, account, location
"expected_result: {}, conversion passed: {:?}, but Location does not match expected pattern, location: {:?}", expected_result, account, location
)
}
},
@@ -737,22 +709,22 @@ mod tests {
// all success
let res_gc_a_p1000 =
GlobalConsensusParachainConvertsFor::<UniversalLocation, [u8; 32]>::convert_location(
&MultiLocation::new(2, X2(GlobalConsensus(ByGenesis([3; 32])), Parachain(1000))),
&Location::new(2, [GlobalConsensus(ByGenesis([3; 32])), Parachain(1000)]),
)
.expect("conversion is ok");
let res_gc_a_p1001 =
GlobalConsensusParachainConvertsFor::<UniversalLocation, [u8; 32]>::convert_location(
&MultiLocation::new(2, X2(GlobalConsensus(ByGenesis([3; 32])), Parachain(1001))),
&Location::new(2, [GlobalConsensus(ByGenesis([3; 32])), Parachain(1001)]),
)
.expect("conversion is ok");
let res_gc_b_p1000 =
GlobalConsensusParachainConvertsFor::<UniversalLocation, [u8; 32]>::convert_location(
&MultiLocation::new(2, X2(GlobalConsensus(ByGenesis([4; 32])), Parachain(1000))),
&Location::new(2, [GlobalConsensus(ByGenesis([4; 32])), Parachain(1000)]),
)
.expect("conversion is ok");
let res_gc_b_p1001 =
GlobalConsensusParachainConvertsFor::<UniversalLocation, [u8; 32]>::convert_location(
&MultiLocation::new(2, X2(GlobalConsensus(ByGenesis([4; 32])), Parachain(1001))),
&Location::new(2, [GlobalConsensus(ByGenesis([4; 32])), Parachain(1001)]),
)
.expect("conversion is ok");
assert_ne!(res_gc_a_p1000, res_gc_a_p1001);
@@ -765,9 +737,9 @@ mod tests {
#[test]
fn remote_account_convert_on_para_sending_para_32() {
let mul = MultiLocation {
let mul = Location {
parents: 1,
interior: X2(Parachain(1), AccountId32 { network: None, id: [0u8; 32] }),
interior: [Parachain(1), AccountId32 { network: None, id: [0u8; 32] }].into(),
};
let rem_1 = ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap();
@@ -779,19 +751,20 @@ mod tests {
rem_1
);
let mul = MultiLocation {
let mul = Location {
parents: 1,
interior: X2(
interior: [
Parachain(1),
AccountId32 { network: Some(NetworkId::Polkadot), id: [0u8; 32] },
),
]
.into(),
};
assert_eq!(ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap(), rem_1);
let mul = MultiLocation {
let mul = Location {
parents: 1,
interior: X2(Parachain(2), AccountId32 { network: None, id: [0u8; 32] }),
interior: [Parachain(2), AccountId32 { network: None, id: [0u8; 32] }].into(),
};
let rem_2 = ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap();
@@ -808,9 +781,9 @@ mod tests {
#[test]
fn remote_account_convert_on_para_sending_para_20() {
let mul = MultiLocation {
let mul = Location {
parents: 1,
interior: X2(Parachain(1), AccountKey20 { network: None, key: [0u8; 20] }),
interior: [Parachain(1), AccountKey20 { network: None, key: [0u8; 20] }].into(),
};
let rem_1 = ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap();
@@ -822,19 +795,20 @@ mod tests {
rem_1
);
let mul = MultiLocation {
let mul = Location {
parents: 1,
interior: X2(
interior: [
Parachain(1),
AccountKey20 { network: Some(NetworkId::Polkadot), key: [0u8; 20] },
),
]
.into(),
};
assert_eq!(ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap(), rem_1);
let mul = MultiLocation {
let mul = Location {
parents: 1,
interior: X2(Parachain(2), AccountKey20 { network: None, key: [0u8; 20] }),
interior: [Parachain(2), AccountKey20 { network: None, key: [0u8; 20] }].into(),
};
let rem_2 = ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap();
@@ -851,9 +825,9 @@ mod tests {
#[test]
fn remote_account_convert_on_para_sending_relay() {
let mul = MultiLocation {
let mul = Location {
parents: 1,
interior: X1(AccountId32 { network: None, id: [0u8; 32] }),
interior: [AccountId32 { network: None, id: [0u8; 32] }].into(),
};
let rem_1 = ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap();
@@ -865,16 +839,16 @@ mod tests {
rem_1
);
let mul = MultiLocation {
let mul = Location {
parents: 1,
interior: X1(AccountId32 { network: Some(NetworkId::Polkadot), id: [0u8; 32] }),
interior: [AccountId32 { network: Some(NetworkId::Polkadot), id: [0u8; 32] }].into(),
};
assert_eq!(ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap(), rem_1);
let mul = MultiLocation {
let mul = Location {
parents: 1,
interior: X1(AccountId32 { network: None, id: [1u8; 32] }),
interior: [AccountId32 { network: None, id: [1u8; 32] }].into(),
};
let rem_2 = ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap();
@@ -891,9 +865,9 @@ mod tests {
#[test]
fn remote_account_convert_on_relay_sending_para_20() {
let mul = MultiLocation {
let mul = Location {
parents: 0,
interior: X2(Parachain(1), AccountKey20 { network: None, key: [0u8; 20] }),
interior: [Parachain(1), AccountKey20 { network: None, key: [0u8; 20] }].into(),
};
let rem_1 = ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap();
@@ -905,9 +879,9 @@ mod tests {
rem_1
);
let mul = MultiLocation {
let mul = Location {
parents: 0,
interior: X2(Parachain(2), AccountKey20 { network: None, key: [0u8; 20] }),
interior: [Parachain(2), AccountKey20 { network: None, key: [0u8; 20] }].into(),
};
let rem_2 = ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap();
@@ -924,9 +898,9 @@ mod tests {
#[test]
fn remote_account_convert_on_relay_sending_para_32() {
let mul = MultiLocation {
let mul = Location {
parents: 0,
interior: X2(Parachain(1), AccountId32 { network: None, id: [0u8; 32] }),
interior: [Parachain(1), AccountId32 { network: None, id: [0u8; 32] }].into(),
};
let rem_1 = ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap();
@@ -938,19 +912,20 @@ mod tests {
rem_1
);
let mul = MultiLocation {
let mul = Location {
parents: 0,
interior: X2(
interior: [
Parachain(1),
AccountId32 { network: Some(NetworkId::Polkadot), id: [0u8; 32] },
),
]
.into(),
};
assert_eq!(ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap(), rem_1);
let mul = MultiLocation {
let mul = Location {
parents: 0,
interior: X2(Parachain(2), AccountId32 { network: None, id: [0u8; 32] }),
interior: [Parachain(2), AccountId32 { network: None, id: [0u8; 32] }].into(),
};
let rem_2 = ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).unwrap();
@@ -966,20 +941,18 @@ mod tests {
}
#[test]
fn remote_account_fails_with_bad_multilocation() {
let mul = MultiLocation {
fn remote_account_fails_with_bad_location() {
let mul = Location {
parents: 1,
interior: X1(AccountKey20 { network: None, key: [0u8; 20] }),
interior: [AccountKey20 { network: None, key: [0u8; 20] }].into(),
};
assert!(ForeignChainAliasAccount::<[u8; 32]>::convert_location(&mul).is_none());
}
#[test]
fn remote_account_convert_on_para_sending_from_remote_para_treasury() {
let relay_treasury_to_para_location = MultiLocation {
parents: 1,
interior: X1(Plurality { id: BodyId::Treasury, part: BodyPart::Voice }),
};
let relay_treasury_to_para_location =
Location::new(1, [Plurality { id: BodyId::Treasury, part: BodyPart::Voice }]);
let actual_description = ForeignChainAliasTreasuryAccount::<[u8; 32]>::convert_location(
&relay_treasury_to_para_location,
)
@@ -993,13 +966,10 @@ mod tests {
actual_description
);
let para_to_para_treasury_location = MultiLocation {
parents: 1,
interior: X2(
Parachain(1001),
Plurality { id: BodyId::Treasury, part: BodyPart::Voice },
),
};
let para_to_para_treasury_location = Location::new(
1,
[Parachain(1001), Plurality { id: BodyId::Treasury, part: BodyPart::Voice }],
);
let actual_description = ForeignChainAliasTreasuryAccount::<[u8; 32]>::convert_location(
&para_to_para_treasury_location,
)
@@ -1016,10 +986,8 @@ mod tests {
#[test]
fn local_account_convert_on_para_from_relay_treasury() {
let location = MultiLocation {
parents: 0,
interior: X1(Plurality { id: BodyId::Treasury, part: BodyPart::Voice }),
};
let location =
Location::new(0, [Plurality { id: BodyId::Treasury, part: BodyPart::Voice }]);
parameter_types! {
pub TreasuryAccountId: AccountId = AccountId::new([42u8; 32]);
+3 -3
View File
@@ -18,7 +18,7 @@
use core::ops::ControlFlow;
use frame_support::traits::ProcessMessageError;
use xcm::latest::{Instruction, MultiLocation};
use xcm::latest::{Instruction, Location};
/// Creates an instruction matcher from an XCM. Since XCM versions differ, we need to make a trait
/// here to unify the interfaces among them.
@@ -67,7 +67,7 @@ impl<'a, Call> CreateMatcher for &'a mut [Instruction<Call>] {
pub trait MatchXcm {
/// The concrete instruction type. Necessary to specify as it changes between XCM versions.
type Inst;
/// The `MultiLocation` type. Necessary to specify as it changes between XCM versions.
/// The `Location` type. Necessary to specify as it changes between XCM versions.
type Loc;
/// The error type to throw when errors happen during matching.
type Error;
@@ -125,7 +125,7 @@ pub struct Matcher<'a, Call> {
impl<'a, Call> MatchXcm for Matcher<'a, Call> {
type Error = ProcessMessageError;
type Inst = Instruction<Call>;
type Loc = MultiLocation;
type Loc = Location;
fn assert_remaining_insts(self, n: usize) -> Result<Self, Self::Error>
where
@@ -14,37 +14,47 @@
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Various implementations and utilities for matching and filtering `MultiLocation` and
//! `InteriorMultiLocation` types.
//! Various implementations and utilities for matching and filtering `Location` and
//! `InteriorLocation` types.
use frame_support::traits::{Contains, Get};
use xcm::latest::{InteriorMultiLocation, MultiLocation, NetworkId};
use xcm::latest::{InteriorLocation, Location, NetworkId};
/// An implementation of `Contains` that checks for `MultiLocation` or
/// `InteriorMultiLocation` if starts with the provided type `T`.
pub struct StartsWith<T>(sp_std::marker::PhantomData<T>);
impl<T: Get<MultiLocation>> Contains<MultiLocation> for StartsWith<T> {
fn contains(t: &MultiLocation) -> bool {
t.starts_with(&T::get())
/// An implementation of `Contains` that checks for `Location` or
/// `InteriorLocation` if starts with the provided type `T`.
pub struct StartsWith<T, L = Location>(sp_std::marker::PhantomData<(T, L)>);
impl<T: Get<L>, L: TryInto<Location> + Clone> Contains<L> for StartsWith<T, L> {
fn contains(location: &L) -> bool {
let latest_location: Location = if let Ok(location) = (*location).clone().try_into() {
location
} else {
return false;
};
let latest_t = if let Ok(location) = T::get().try_into() {
location
} else {
return false;
};
latest_location.starts_with(&latest_t)
}
}
impl<T: Get<InteriorMultiLocation>> Contains<InteriorMultiLocation> for StartsWith<T> {
fn contains(t: &InteriorMultiLocation) -> bool {
impl<T: Get<InteriorLocation>> Contains<InteriorLocation> for StartsWith<T> {
fn contains(t: &InteriorLocation) -> bool {
t.starts_with(&T::get())
}
}
/// An implementation of `Contains` that checks for `MultiLocation` or
/// `InteriorMultiLocation` if starts with expected `GlobalConsensus(NetworkId)` provided as type
/// An implementation of `Contains` that checks for `Location` or
/// `InteriorLocation` if starts with expected `GlobalConsensus(NetworkId)` provided as type
/// `T`.
pub struct StartsWithExplicitGlobalConsensus<T>(sp_std::marker::PhantomData<T>);
impl<T: Get<NetworkId>> Contains<MultiLocation> for StartsWithExplicitGlobalConsensus<T> {
fn contains(location: &MultiLocation) -> bool {
matches!(location.interior.global_consensus(), Ok(requested_network) if requested_network.eq(&T::get()))
impl<T: Get<NetworkId>> Contains<Location> for StartsWithExplicitGlobalConsensus<T> {
fn contains(location: &Location) -> bool {
matches!(location.interior().global_consensus(), Ok(requested_network) if requested_network.eq(&T::get()))
}
}
impl<T: Get<NetworkId>> Contains<InteriorMultiLocation> for StartsWithExplicitGlobalConsensus<T> {
fn contains(location: &InteriorMultiLocation) -> bool {
impl<T: Get<NetworkId>> Contains<InteriorLocation> for StartsWithExplicitGlobalConsensus<T> {
fn contains(location: &InteriorLocation) -> bool {
matches!(location.global_consensus(), Ok(requested_network) if requested_network.eq(&T::get()))
}
}
+11 -56
View File
@@ -19,25 +19,24 @@
use frame_support::traits::Get;
use sp_std::marker::PhantomData;
use xcm::latest::{
AssetId::{Abstract, Concrete},
AssetInstance,
Asset, AssetId, AssetInstance,
Fungibility::{Fungible, NonFungible},
MultiAsset, MultiLocation,
Location,
};
use xcm_executor::traits::{MatchesFungible, MatchesNonFungible};
/// Converts a `MultiAsset` into balance `B` if it is a concrete fungible with an id equal to that
/// Converts a `Asset` into balance `B` if its id is equal to that
/// given by `T`'s `Get`.
///
/// # Example
///
/// ```
/// use xcm::latest::{MultiLocation, Parent};
/// use xcm::latest::{Location, Parent};
/// use staging_xcm_builder::IsConcrete;
/// use xcm_executor::traits::MatchesFungible;
///
/// frame_support::parameter_types! {
/// pub TargetLocation: MultiLocation = Parent.into();
/// pub TargetLocation: Location = Parent.into();
/// }
///
/// # fn main() {
@@ -47,62 +46,18 @@ use xcm_executor::traits::{MatchesFungible, MatchesNonFungible};
/// # }
/// ```
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> {
impl<T: Get<Location>, B: TryFrom<u128>> MatchesFungible<B> for IsConcrete<T> {
fn matches_fungible(a: &Asset) -> Option<B> {
match (&a.id, &a.fun) {
(Concrete(ref id), Fungible(ref amount)) if id == &T::get() =>
(*amount).try_into().ok(),
(AssetId(ref id), Fungible(ref amount)) if id == &T::get() => (*amount).try_into().ok(),
_ => None,
}
}
}
impl<T: Get<MultiLocation>, I: TryFrom<AssetInstance>> MatchesNonFungible<I> for IsConcrete<T> {
fn matches_nonfungible(a: &MultiAsset) -> Option<I> {
impl<T: Get<Location>, I: TryFrom<AssetInstance>> MatchesNonFungible<I> for IsConcrete<T> {
fn matches_nonfungible(a: &Asset) -> Option<I> {
match (&a.id, &a.fun) {
(Concrete(id), NonFungible(instance)) if id == &T::get() => (*instance).try_into().ok(),
_ => None,
}
}
}
/// Same as [`IsConcrete`] but for a fungible with abstract location.
///
/// # Example
///
/// ```
/// use xcm::latest::prelude::*;
/// use staging_xcm_builder::IsAbstract;
/// use xcm_executor::traits::{MatchesFungible, MatchesNonFungible};
///
/// frame_support::parameter_types! {
/// pub TargetLocation: [u8; 32] = [7u8; 32];
/// }
///
/// # fn main() {
/// let asset = ([7u8; 32], 999u128).into();
/// // match `asset` if it is an abstract asset in `TargetLocation`.
/// assert_eq!(<IsAbstract<TargetLocation> as MatchesFungible<u128>>::matches_fungible(&asset), Some(999));
/// let nft = ([7u8; 32], [42u8; 4]).into();
/// assert_eq!(
/// <IsAbstract<TargetLocation> as MatchesNonFungible<[u8; 4]>>::matches_nonfungible(&nft),
/// Some([42u8; 4])
/// );
/// # }
/// ```
pub struct IsAbstract<T>(PhantomData<T>);
impl<T: Get<[u8; 32]>, B: TryFrom<u128>> MatchesFungible<B> for IsAbstract<T> {
fn matches_fungible(a: &MultiAsset) -> Option<B> {
match (&a.id, &a.fun) {
(Abstract(ref id), Fungible(ref amount)) if id == &T::get() =>
(*amount).try_into().ok(),
_ => None,
}
}
}
impl<T: Get<[u8; 32]>, B: TryFrom<AssetInstance>> MatchesNonFungible<B> for IsAbstract<T> {
fn matches_nonfungible(a: &MultiAsset) -> Option<B> {
match (&a.id, &a.fun) {
(Abstract(id), NonFungible(instance)) if id == &T::get() => (*instance).try_into().ok(),
(AssetId(id), NonFungible(instance)) if id == &T::get() => (*instance).try_into().ok(),
_ => None,
}
}
@@ -40,11 +40,11 @@ impl<
> TransactAsset for NonFungiblesTransferAdapter<Assets, Matcher, AccountIdConverter, AccountId>
{
fn transfer_asset(
what: &MultiAsset,
from: &MultiLocation,
to: &MultiLocation,
what: &Asset,
from: &Location,
to: &Location,
context: &XcmContext,
) -> result::Result<xcm_executor::Assets, XcmError> {
) -> result::Result<xcm_executor::AssetsInHolding, XcmError> {
log::trace!(
target: LOG_TARGET,
"transfer_asset what: {:?}, from: {:?}, to: {:?}, context: {:?}",
@@ -131,7 +131,7 @@ impl<
CheckingAccount,
>
{
fn can_check_in(_origin: &MultiLocation, what: &MultiAsset, context: &XcmContext) -> XcmResult {
fn can_check_in(_origin: &Location, what: &Asset, context: &XcmContext) -> XcmResult {
log::trace!(
target: LOG_TARGET,
"can_check_in origin: {:?}, what: {:?}, context: {:?}",
@@ -150,7 +150,7 @@ impl<
}
}
fn check_in(_origin: &MultiLocation, what: &MultiAsset, context: &XcmContext) {
fn check_in(_origin: &Location, what: &Asset, context: &XcmContext) {
log::trace!(
target: LOG_TARGET,
"check_in origin: {:?}, what: {:?}, context: {:?}",
@@ -169,7 +169,7 @@ impl<
}
}
fn can_check_out(_dest: &MultiLocation, what: &MultiAsset, context: &XcmContext) -> XcmResult {
fn can_check_out(_dest: &Location, what: &Asset, context: &XcmContext) -> XcmResult {
log::trace!(
target: LOG_TARGET,
"can_check_out dest: {:?}, what: {:?}, context: {:?}",
@@ -188,7 +188,7 @@ impl<
}
}
fn check_out(_dest: &MultiLocation, what: &MultiAsset, context: &XcmContext) {
fn check_out(_dest: &Location, what: &Asset, context: &XcmContext) {
log::trace!(
target: LOG_TARGET,
"check_out dest: {:?}, what: {:?}, context: {:?}",
@@ -207,11 +207,7 @@ impl<
}
}
fn deposit_asset(
what: &MultiAsset,
who: &MultiLocation,
context: Option<&XcmContext>,
) -> XcmResult {
fn deposit_asset(what: &Asset, who: &Location, context: Option<&XcmContext>) -> XcmResult {
log::trace!(
target: LOG_TARGET,
"deposit_asset what: {:?}, who: {:?}, context: {:?}",
@@ -228,10 +224,10 @@ impl<
}
fn withdraw_asset(
what: &MultiAsset,
who: &MultiLocation,
what: &Asset,
who: &Location,
maybe_context: Option<&XcmContext>,
) -> result::Result<xcm_executor::Assets, XcmError> {
) -> result::Result<xcm_executor::AssetsInHolding, XcmError> {
log::trace!(
target: LOG_TARGET,
"withdraw_asset what: {:?}, who: {:?}, maybe_context: {:?}",
@@ -267,7 +263,7 @@ impl<
> TransactAsset
for NonFungiblesAdapter<Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount>
{
fn can_check_in(origin: &MultiLocation, what: &MultiAsset, context: &XcmContext) -> XcmResult {
fn can_check_in(origin: &Location, what: &Asset, context: &XcmContext) -> XcmResult {
NonFungiblesMutateAdapter::<
Assets,
Matcher,
@@ -278,7 +274,7 @@ impl<
>::can_check_in(origin, what, context)
}
fn check_in(origin: &MultiLocation, what: &MultiAsset, context: &XcmContext) {
fn check_in(origin: &Location, what: &Asset, context: &XcmContext) {
NonFungiblesMutateAdapter::<
Assets,
Matcher,
@@ -289,7 +285,7 @@ impl<
>::check_in(origin, what, context)
}
fn can_check_out(dest: &MultiLocation, what: &MultiAsset, context: &XcmContext) -> XcmResult {
fn can_check_out(dest: &Location, what: &Asset, context: &XcmContext) -> XcmResult {
NonFungiblesMutateAdapter::<
Assets,
Matcher,
@@ -300,7 +296,7 @@ impl<
>::can_check_out(dest, what, context)
}
fn check_out(dest: &MultiLocation, what: &MultiAsset, context: &XcmContext) {
fn check_out(dest: &Location, what: &Asset, context: &XcmContext) {
NonFungiblesMutateAdapter::<
Assets,
Matcher,
@@ -311,11 +307,7 @@ impl<
>::check_out(dest, what, context)
}
fn deposit_asset(
what: &MultiAsset,
who: &MultiLocation,
context: Option<&XcmContext>,
) -> XcmResult {
fn deposit_asset(what: &Asset, who: &Location, context: Option<&XcmContext>) -> XcmResult {
NonFungiblesMutateAdapter::<
Assets,
Matcher,
@@ -327,10 +319,10 @@ impl<
}
fn withdraw_asset(
what: &MultiAsset,
who: &MultiLocation,
what: &Asset,
who: &Location,
maybe_context: Option<&XcmContext>,
) -> result::Result<xcm_executor::Assets, XcmError> {
) -> result::Result<xcm_executor::AssetsInHolding, XcmError> {
NonFungiblesMutateAdapter::<
Assets,
Matcher,
@@ -342,11 +334,11 @@ impl<
}
fn transfer_asset(
what: &MultiAsset,
from: &MultiLocation,
to: &MultiLocation,
what: &Asset,
from: &Location,
to: &Location,
context: &XcmContext,
) -> result::Result<xcm_executor::Assets, XcmError> {
) -> result::Result<xcm_executor::AssetsInHolding, XcmError> {
NonFungiblesTransferAdapter::<Assets, Matcher, AccountIdConverter, AccountId>::transfer_asset(
what, from, to, context,
)
@@ -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/>.
//! Implementation for `ContainsPair<MultiLocation, MultiLocation>`.
//! Implementation for `ContainsPair<Location, Location>`.
use frame_support::traits::{Contains, ContainsPair};
use sp_std::marker::PhantomData;
@@ -25,13 +25,15 @@ use xcm::latest::prelude::*;
///
/// Requires that the prefixed origin `AccountId32` matches the target `AccountId32`.
pub struct AliasForeignAccountId32<Prefix>(PhantomData<Prefix>);
impl<Prefix: Contains<MultiLocation>> ContainsPair<MultiLocation, MultiLocation>
impl<Prefix: Contains<Location>> ContainsPair<Location, Location>
for AliasForeignAccountId32<Prefix>
{
fn contains(origin: &MultiLocation, target: &MultiLocation) -> bool {
if let (prefix, Some(account_id @ AccountId32 { .. })) = origin.split_last_interior() {
fn contains(origin: &Location, target: &Location) -> bool {
if let (prefix, Some(account_id @ AccountId32 { .. })) =
origin.clone().split_last_interior()
{
return Prefix::contains(&prefix) &&
*target == MultiLocation { parents: 0, interior: X1(account_id) }
*target == Location { parents: 0, interior: [account_id].into() }
}
false
}
@@ -21,7 +21,7 @@ use frame_system::RawOrigin as SystemRawOrigin;
use polkadot_parachain_primitives::primitives::IsSystem;
use sp_runtime::traits::TryConvert;
use sp_std::marker::PhantomData;
use xcm::latest::{BodyId, BodyPart, Junction, Junctions::*, MultiLocation, NetworkId, OriginKind};
use xcm::latest::{BodyId, BodyPart, Junction, Junctions::*, Location, NetworkId, OriginKind};
use xcm_executor::traits::{ConvertLocation, ConvertOrigin};
/// Sovereign accounts use the system's `Signed` origin with an account ID derived from the
@@ -35,9 +35,9 @@ where
RuntimeOrigin::AccountId: Clone,
{
fn convert_origin(
origin: impl Into<MultiLocation>,
origin: impl Into<Location>,
kind: OriginKind,
) -> Result<RuntimeOrigin, MultiLocation> {
) -> Result<RuntimeOrigin, Location> {
let origin = origin.into();
log::trace!(
target: "xcm::origin_conversion",
@@ -56,9 +56,9 @@ where
pub struct ParentAsSuperuser<RuntimeOrigin>(PhantomData<RuntimeOrigin>);
impl<RuntimeOrigin: OriginTrait> ConvertOrigin<RuntimeOrigin> for ParentAsSuperuser<RuntimeOrigin> {
fn convert_origin(
origin: impl Into<MultiLocation>,
origin: impl Into<Location>,
kind: OriginKind,
) -> Result<RuntimeOrigin, MultiLocation> {
) -> Result<RuntimeOrigin, Location> {
let origin = origin.into();
log::trace!(target: "xcm::origin_conversion", "ParentAsSuperuser origin: {:?}, kind: {:?}", origin, kind);
if kind == OriginKind::Superuser && origin.contains_parents_only(1) {
@@ -76,17 +76,16 @@ impl<ParaId: IsSystem + From<u32>, RuntimeOrigin: OriginTrait> ConvertOrigin<Run
for ChildSystemParachainAsSuperuser<ParaId, RuntimeOrigin>
{
fn convert_origin(
origin: impl Into<MultiLocation>,
origin: impl Into<Location>,
kind: OriginKind,
) -> Result<RuntimeOrigin, MultiLocation> {
) -> Result<RuntimeOrigin, Location> {
let origin = origin.into();
log::trace!(target: "xcm::origin_conversion", "ChildSystemParachainAsSuperuser origin: {:?}, kind: {:?}", origin, kind);
match (kind, origin) {
(
OriginKind::Superuser,
MultiLocation { parents: 0, interior: X1(Junction::Parachain(id)) },
) if ParaId::from(id).is_system() => Ok(RuntimeOrigin::root()),
(_, origin) => Err(origin),
match (kind, origin.unpack()) {
(OriginKind::Superuser, (0, [Junction::Parachain(id)]))
if ParaId::from(*id).is_system() =>
Ok(RuntimeOrigin::root()),
_ => Err(origin),
}
}
}
@@ -98,21 +97,20 @@ impl<ParaId: IsSystem + From<u32>, RuntimeOrigin: OriginTrait> ConvertOrigin<Run
for SiblingSystemParachainAsSuperuser<ParaId, RuntimeOrigin>
{
fn convert_origin(
origin: impl Into<MultiLocation>,
origin: impl Into<Location>,
kind: OriginKind,
) -> Result<RuntimeOrigin, MultiLocation> {
) -> Result<RuntimeOrigin, Location> {
let origin = origin.into();
log::trace!(
target: "xcm::origin_conversion",
"SiblingSystemParachainAsSuperuser origin: {:?}, kind: {:?}",
origin, kind,
);
match (kind, origin) {
(
OriginKind::Superuser,
MultiLocation { parents: 1, interior: X1(Junction::Parachain(id)) },
) if ParaId::from(id).is_system() => Ok(RuntimeOrigin::root()),
(_, origin) => Err(origin),
match (kind, origin.unpack()) {
(OriginKind::Superuser, (1, [Junction::Parachain(id)]))
if ParaId::from(*id).is_system() =>
Ok(RuntimeOrigin::root()),
_ => Err(origin),
}
}
}
@@ -124,17 +122,15 @@ impl<ParachainOrigin: From<u32>, RuntimeOrigin: From<ParachainOrigin>> ConvertOr
for ChildParachainAsNative<ParachainOrigin, RuntimeOrigin>
{
fn convert_origin(
origin: impl Into<MultiLocation>,
origin: impl Into<Location>,
kind: OriginKind,
) -> Result<RuntimeOrigin, MultiLocation> {
) -> Result<RuntimeOrigin, Location> {
let origin = origin.into();
log::trace!(target: "xcm::origin_conversion", "ChildParachainAsNative origin: {:?}, kind: {:?}", origin, kind);
match (kind, origin) {
(
OriginKind::Native,
MultiLocation { parents: 0, interior: X1(Junction::Parachain(id)) },
) => Ok(RuntimeOrigin::from(ParachainOrigin::from(id))),
(_, origin) => Err(origin),
match (kind, origin.unpack()) {
(OriginKind::Native, (0, [Junction::Parachain(id)])) =>
Ok(RuntimeOrigin::from(ParachainOrigin::from(*id))),
_ => Err(origin),
}
}
}
@@ -146,21 +142,19 @@ impl<ParachainOrigin: From<u32>, RuntimeOrigin: From<ParachainOrigin>> ConvertOr
for SiblingParachainAsNative<ParachainOrigin, RuntimeOrigin>
{
fn convert_origin(
origin: impl Into<MultiLocation>,
origin: impl Into<Location>,
kind: OriginKind,
) -> Result<RuntimeOrigin, MultiLocation> {
) -> Result<RuntimeOrigin, Location> {
let origin = origin.into();
log::trace!(
target: "xcm::origin_conversion",
"SiblingParachainAsNative origin: {:?}, kind: {:?}",
origin, kind,
);
match (kind, origin) {
(
OriginKind::Native,
MultiLocation { parents: 1, interior: X1(Junction::Parachain(id)) },
) => Ok(RuntimeOrigin::from(ParachainOrigin::from(id))),
(_, origin) => Err(origin),
match (kind, origin.unpack()) {
(OriginKind::Native, (1, [Junction::Parachain(id)])) =>
Ok(RuntimeOrigin::from(ParachainOrigin::from(*id))),
_ => Err(origin),
}
}
}
@@ -173,9 +167,9 @@ impl<RelayOrigin: Get<RuntimeOrigin>, RuntimeOrigin> ConvertOrigin<RuntimeOrigin
for RelayChainAsNative<RelayOrigin, RuntimeOrigin>
{
fn convert_origin(
origin: impl Into<MultiLocation>,
origin: impl Into<Location>,
kind: OriginKind,
) -> Result<RuntimeOrigin, MultiLocation> {
) -> Result<RuntimeOrigin, Location> {
let origin = origin.into();
log::trace!(target: "xcm::origin_conversion", "RelayChainAsNative origin: {:?}, kind: {:?}", origin, kind);
if kind == OriginKind::Native && origin.contains_parents_only(1) {
@@ -193,22 +187,20 @@ where
RuntimeOrigin::AccountId: From<[u8; 32]>,
{
fn convert_origin(
origin: impl Into<MultiLocation>,
origin: impl Into<Location>,
kind: OriginKind,
) -> Result<RuntimeOrigin, MultiLocation> {
) -> Result<RuntimeOrigin, Location> {
let origin = origin.into();
log::trace!(
target: "xcm::origin_conversion",
"SignedAccountId32AsNative origin: {:?}, kind: {:?}",
origin, kind,
);
match (kind, origin) {
(
OriginKind::Native,
MultiLocation { parents: 0, interior: X1(Junction::AccountId32 { id, network }) },
) if matches!(network, None) || network == Network::get() =>
Ok(RuntimeOrigin::signed(id.into())),
(_, origin) => Err(origin),
match (kind, origin.unpack()) {
(OriginKind::Native, (0, [Junction::AccountId32 { id, network }]))
if matches!(network, None) || *network == Network::get() =>
Ok(RuntimeOrigin::signed((*id).into())),
_ => Err(origin),
}
}
}
@@ -222,34 +214,32 @@ where
RuntimeOrigin::AccountId: From<[u8; 20]>,
{
fn convert_origin(
origin: impl Into<MultiLocation>,
origin: impl Into<Location>,
kind: OriginKind,
) -> Result<RuntimeOrigin, MultiLocation> {
) -> Result<RuntimeOrigin, Location> {
let origin = origin.into();
log::trace!(
target: "xcm::origin_conversion",
"SignedAccountKey20AsNative origin: {:?}, kind: {:?}",
origin, kind,
);
match (kind, origin) {
(
OriginKind::Native,
MultiLocation { parents: 0, interior: X1(Junction::AccountKey20 { key, network }) },
) if (matches!(network, None) || network == Network::get()) =>
Ok(RuntimeOrigin::signed(key.into())),
(_, origin) => Err(origin),
match (kind, origin.unpack()) {
(OriginKind::Native, (0, [Junction::AccountKey20 { key, network }]))
if (matches!(network, None) || *network == Network::get()) =>
Ok(RuntimeOrigin::signed((*key).into())),
_ => Err(origin),
}
}
}
/// `EnsureOrigin` barrier to convert from dispatch origin to XCM origin, if one exists.
pub struct EnsureXcmOrigin<RuntimeOrigin, Conversion>(PhantomData<(RuntimeOrigin, Conversion)>);
impl<RuntimeOrigin: OriginTrait + Clone, Conversion: TryConvert<RuntimeOrigin, MultiLocation>>
impl<RuntimeOrigin: OriginTrait + Clone, Conversion: TryConvert<RuntimeOrigin, Location>>
EnsureOrigin<RuntimeOrigin> for EnsureXcmOrigin<RuntimeOrigin, Conversion>
where
RuntimeOrigin::PalletsOrigin: PartialEq,
{
type Success = MultiLocation;
type Success = Location;
fn try_origin(o: RuntimeOrigin) -> Result<Self::Success, RuntimeOrigin> {
let o = match Conversion::try_convert(o) {
Ok(location) => return Ok(location),
@@ -282,13 +272,12 @@ impl<
RuntimeOrigin: OriginTrait + Clone,
AccountId: Into<[u8; 32]>,
Network: Get<Option<NetworkId>>,
> TryConvert<RuntimeOrigin, MultiLocation>
for SignedToAccountId32<RuntimeOrigin, AccountId, Network>
> TryConvert<RuntimeOrigin, Location> for SignedToAccountId32<RuntimeOrigin, AccountId, Network>
where
RuntimeOrigin::PalletsOrigin: From<SystemRawOrigin<AccountId>>
+ TryInto<SystemRawOrigin<AccountId>, Error = RuntimeOrigin::PalletsOrigin>,
{
fn try_convert(o: RuntimeOrigin) -> Result<MultiLocation, RuntimeOrigin> {
fn try_convert(o: RuntimeOrigin) -> Result<Location, RuntimeOrigin> {
o.try_with_caller(|caller| match caller.try_into() {
Ok(SystemRawOrigin::Signed(who)) =>
Ok(Junction::AccountId32 { network: Network::get(), id: who.into() }.into()),
@@ -299,7 +288,7 @@ where
}
/// `Convert` implementation to convert from some an origin which implements `Backing` into a
/// corresponding `Plurality` `MultiLocation`.
/// corresponding `Plurality` `Location`.
///
/// Typically used when configuring `pallet-xcm` for allowing a collective's Origin to dispatch an
/// XCM from a `Plurality` origin.
@@ -307,12 +296,12 @@ pub struct BackingToPlurality<RuntimeOrigin, COrigin, Body>(
PhantomData<(RuntimeOrigin, COrigin, Body)>,
);
impl<RuntimeOrigin: OriginTrait + Clone, COrigin: GetBacking, Body: Get<BodyId>>
TryConvert<RuntimeOrigin, MultiLocation> for BackingToPlurality<RuntimeOrigin, COrigin, Body>
TryConvert<RuntimeOrigin, Location> for BackingToPlurality<RuntimeOrigin, COrigin, Body>
where
RuntimeOrigin::PalletsOrigin:
From<COrigin> + TryInto<COrigin, Error = RuntimeOrigin::PalletsOrigin>,
{
fn try_convert(o: RuntimeOrigin) -> Result<MultiLocation, RuntimeOrigin> {
fn try_convert(o: RuntimeOrigin) -> Result<Location, RuntimeOrigin> {
o.try_with_caller(|caller| match caller.try_into() {
Ok(co) => match co.get_backing() {
Some(backing) => Ok(Junction::Plurality {
@@ -333,10 +322,10 @@ pub struct OriginToPluralityVoice<RuntimeOrigin, EnsureBodyOrigin, Body>(
PhantomData<(RuntimeOrigin, EnsureBodyOrigin, Body)>,
);
impl<RuntimeOrigin: Clone, EnsureBodyOrigin: EnsureOrigin<RuntimeOrigin>, Body: Get<BodyId>>
TryConvert<RuntimeOrigin, MultiLocation>
TryConvert<RuntimeOrigin, Location>
for OriginToPluralityVoice<RuntimeOrigin, EnsureBodyOrigin, Body>
{
fn try_convert(o: RuntimeOrigin) -> Result<MultiLocation, RuntimeOrigin> {
fn try_convert(o: RuntimeOrigin) -> Result<Location, RuntimeOrigin> {
match EnsureBodyOrigin::try_origin(o) {
Ok(_) => Ok(Junction::Plurality { id: Body::get(), part: BodyPart::Voice }.into()),
Err(o) => Err(o),
+10 -11
View File
@@ -30,7 +30,7 @@ use xcm_executor::traits::{QueryHandler, QueryResponseStatus};
/// ownership of some `Interior` location of the local chain to a particular `Beneficiary`. The
/// `AssetKind` value is not itself bounded (to avoid the issue of needing to wrap some preexisting
/// datatype), however a converter type `AssetKindToLocatableAsset` must be provided in order to
/// translate it into a `LocatableAsset`, which comprises both an XCM `MultiLocation` describing
/// translate it into a `LocatableAsset`, which comprises both an XCM `Location` describing
/// the XCM endpoint on which the asset to be paid resides and an XCM `AssetId` to identify the
/// specific asset at that endpoint.
///
@@ -65,14 +65,14 @@ pub struct PayOverXcm<
)>,
);
impl<
Interior: Get<InteriorMultiLocation>,
Interior: Get<InteriorLocation>,
Router: SendXcm,
Querier: QueryHandler,
Timeout: Get<Querier::BlockNumber>,
Beneficiary: Clone,
AssetKind,
AssetKindToLocatableAsset: TryConvert<AssetKind, LocatableAssetId>,
BeneficiaryRefToLocation: for<'a> TryConvert<&'a Beneficiary, MultiLocation>,
BeneficiaryRefToLocation: for<'a> TryConvert<&'a Beneficiary, Location>,
> Pay
for PayOverXcm<
Interior,
@@ -105,7 +105,7 @@ impl<
let beneficiary = BeneficiaryRefToLocation::try_convert(&who)
.map_err(|_| xcm::latest::Error::InvalidLocation)?;
let query_id = Querier::new_query(asset_location, Timeout::get(), Interior::get());
let query_id = Querier::new_query(asset_location.clone(), Timeout::get(), Interior::get());
let message = Xcm(vec![
DescendOrigin(Interior::get()),
@@ -120,8 +120,7 @@ impl<
])),
TransferAsset {
beneficiary,
assets: vec![MultiAsset { id: asset_id, fun: Fungibility::Fungible(amount) }]
.into(),
assets: vec![Asset { id: asset_id, fun: Fungibility::Fungible(amount) }].into(),
},
]);
@@ -195,16 +194,16 @@ pub struct LocatableAssetId {
/// The asset's ID.
pub asset_id: AssetId,
/// The (relative) location in which the asset ID is meaningful.
pub location: MultiLocation,
pub location: Location,
}
/// Adapter `struct` which implements a conversion from any `AssetKind` into a [`LocatableAssetId`]
/// value using a fixed `Location` for the `location` field.
pub struct FixedLocation<Location>(sp_std::marker::PhantomData<Location>);
impl<Location: Get<MultiLocation>, AssetKind: Into<AssetId>> TryConvert<AssetKind, LocatableAssetId>
for FixedLocation<Location>
pub struct FixedLocation<FixedLocationValue>(sp_std::marker::PhantomData<FixedLocationValue>);
impl<FixedLocationValue: Get<Location>, AssetKind: Into<AssetId>>
TryConvert<AssetKind, LocatableAssetId> for FixedLocation<FixedLocationValue>
{
fn try_convert(value: AssetKind) -> Result<LocatableAssetId, AssetKind> {
Ok(LocatableAssetId { asset_id: value.into(), location: Location::get() })
Ok(LocatableAssetId { asset_id: value.into(), location: FixedLocationValue::get() })
}
}
@@ -30,7 +30,7 @@ pub struct ProcessXcmMessage<MessageOrigin, XcmExecutor, Call>(
PhantomData<(MessageOrigin, XcmExecutor, Call)>,
);
impl<
MessageOrigin: Into<MultiLocation> + FullCodec + MaxEncodedLen + Clone + Eq + PartialEq + TypeInfo + Debug,
MessageOrigin: Into<Location> + FullCodec + MaxEncodedLen + Clone + Eq + PartialEq + TypeInfo + Debug,
XcmExecutor: ExecuteXcm<Call>,
Call,
> ProcessMessage for ProcessXcmMessage<MessageOrigin, XcmExecutor, Call>
@@ -82,28 +82,26 @@ impl<
let (consumed, result) = match XcmExecutor::execute(origin.into(), pre, id, Weight::zero())
{
Outcome::Complete(w) => {
Outcome::Complete { used } => {
log::trace!(
target: LOG_TARGET,
"XCM message execution complete, used weight: {w}",
"XCM message execution complete, used weight: {used}",
);
(w, Ok(true))
(used, Ok(true))
},
Outcome::Incomplete(w, e) => {
Outcome::Incomplete { used, error } => {
log::trace!(
target: LOG_TARGET,
"XCM message execution incomplete, used weight: {w}, error: {e:?}",
"XCM message execution incomplete, used weight: {used}, error: {error:?}",
);
(w, Ok(false))
(used, Ok(false))
},
// In the error-case we assume the worst case and consume all possible weight.
Outcome::Error(e) => {
Outcome::Error { error } => {
log::trace!(
target: LOG_TARGET,
"XCM message execution error: {e:?}",
"XCM message execution error: {error:?}",
);
(required, Err(ProcessMessageError::Unsupported))
},
};
+2 -2
View File
@@ -38,7 +38,7 @@ impl<Inner: SendXcm> SendXcm for WithUniqueTopic<Inner> {
type Ticket = (Inner::Ticket, [u8; 32]);
fn validate(
destination: &mut Option<MultiLocation>,
destination: &mut Option<Location>,
message: &mut Option<Xcm<()>>,
) -> SendResult<Self::Ticket> {
let mut message = message.take().ok_or(SendError::MissingArgument)?;
@@ -82,7 +82,7 @@ impl<Inner: SendXcm, TopicSource: SourceTopic> SendXcm for WithTopicSource<Inner
type Ticket = (Inner::Ticket, [u8; 32]);
fn validate(
destination: &mut Option<MultiLocation>,
destination: &mut Option<Location>,
message: &mut Option<Xcm<()>>,
) -> SendResult<Self::Ticket> {
let mut message = message.take().ok_or(SendError::MissingArgument)?;
+37 -37
View File
@@ -27,11 +27,11 @@ pub use xcm_executor::{
traits::{
AssetExchange, AssetLock, ConvertOrigin, Enact, LockError, OnResponse, TransactAsset,
},
Assets, Config,
AssetsInHolding, Config,
};
parameter_types! {
pub static SubscriptionRequests: Vec<(MultiLocation, Option<(QueryId, Weight)>)> = vec![];
pub static SubscriptionRequests: Vec<(Location, Option<(QueryId, Weight)>)> = vec![];
pub static MaxAssetsIntoHolding: u32 = 4;
}
@@ -39,39 +39,39 @@ pub struct TestSubscriptionService;
impl VersionChangeNotifier for TestSubscriptionService {
fn start(
location: &MultiLocation,
location: &Location,
query_id: QueryId,
max_weight: Weight,
_context: &XcmContext,
) -> XcmResult {
let mut r = SubscriptionRequests::get();
r.push((*location, Some((query_id, max_weight))));
r.push((location.clone(), Some((query_id, max_weight))));
SubscriptionRequests::set(r);
Ok(())
}
fn stop(location: &MultiLocation, _context: &XcmContext) -> XcmResult {
fn stop(location: &Location, _context: &XcmContext) -> XcmResult {
let mut r = SubscriptionRequests::get();
r.retain(|(l, _q)| l != location);
r.push((*location, None));
r.push((location.clone(), None));
SubscriptionRequests::set(r);
Ok(())
}
fn is_subscribed(location: &MultiLocation) -> bool {
fn is_subscribed(location: &Location) -> bool {
let r = SubscriptionRequests::get();
r.iter().any(|(l, q)| l == location && q.is_some())
}
}
parameter_types! {
pub static TrappedAssets: Vec<(MultiLocation, MultiAssets)> = vec![];
pub static TrappedAssets: Vec<(Location, Assets)> = vec![];
}
pub struct TestAssetTrap;
impl DropAssets for TestAssetTrap {
fn drop_assets(origin: &MultiLocation, assets: Assets, _context: &XcmContext) -> Weight {
let mut t: Vec<(MultiLocation, MultiAssets)> = TrappedAssets::get();
t.push((*origin, assets.into()));
fn drop_assets(origin: &Location, assets: AssetsInHolding, _context: &XcmContext) -> Weight {
let mut t: Vec<(Location, Assets)> = TrappedAssets::get();
t.push((origin.clone(), assets.into()));
TrappedAssets::set(t);
Weight::from_parts(5, 5)
}
@@ -79,13 +79,13 @@ impl DropAssets for TestAssetTrap {
impl ClaimAssets for TestAssetTrap {
fn claim_assets(
origin: &MultiLocation,
ticket: &MultiLocation,
what: &MultiAssets,
origin: &Location,
ticket: &Location,
what: &Assets,
_context: &XcmContext,
) -> bool {
let mut t: Vec<(MultiLocation, MultiAssets)> = TrappedAssets::get();
if let (0, X1(GeneralIndex(i))) = (ticket.parents, &ticket.interior) {
let mut t: Vec<(Location, Assets)> = TrappedAssets::get();
if let (0, [GeneralIndex(i)]) = ticket.unpack() {
if let Some((l, a)) = t.get(*i as usize) {
if l == origin && a == what {
t.swap_remove(*i as usize);
@@ -102,11 +102,11 @@ pub struct TestAssetExchanger;
impl AssetExchange for TestAssetExchanger {
fn exchange_asset(
_origin: Option<&MultiLocation>,
_give: Assets,
want: &MultiAssets,
_origin: Option<&Location>,
_give: AssetsInHolding,
want: &Assets,
_maximal: bool,
) -> Result<Assets, Assets> {
) -> Result<AssetsInHolding, AssetsInHolding> {
Ok(want.clone().into())
}
}
@@ -135,17 +135,17 @@ impl PalletsInfoAccess for TestPalletsInfo {
}
pub struct TestUniversalAliases;
impl Contains<(MultiLocation, Junction)> for TestUniversalAliases {
fn contains(aliases: &(MultiLocation, Junction)) -> bool {
impl Contains<(Location, Junction)> for TestUniversalAliases {
fn contains(aliases: &(Location, Junction)) -> bool {
&aliases.0 == &Here.into_location() && &aliases.1 == &GlobalConsensus(ByGenesis([0; 32]))
}
}
parameter_types! {
pub static LockedAssets: Vec<(MultiLocation, MultiAsset)> = vec![];
pub static LockedAssets: Vec<(Location, Asset)> = vec![];
}
pub struct TestLockTicket(MultiLocation, MultiAsset);
pub struct TestLockTicket(Location, Asset);
impl Enact for TestLockTicket {
fn enact(self) -> Result<(), LockError> {
let mut locked_assets = LockedAssets::get();
@@ -154,7 +154,7 @@ impl Enact for TestLockTicket {
Ok(())
}
}
pub struct TestUnlockTicket(MultiLocation, MultiAsset);
pub struct TestUnlockTicket(Location, Asset);
impl Enact for TestUnlockTicket {
fn enact(self) -> Result<(), LockError> {
let mut locked_assets = LockedAssets::get();
@@ -183,33 +183,33 @@ impl AssetLock for TestAssetLocker {
type ReduceTicket = TestReduceTicket;
fn prepare_lock(
unlocker: MultiLocation,
asset: MultiAsset,
_owner: MultiLocation,
unlocker: Location,
asset: Asset,
_owner: Location,
) -> Result<TestLockTicket, LockError> {
Ok(TestLockTicket(unlocker, asset))
}
fn prepare_unlock(
unlocker: MultiLocation,
asset: MultiAsset,
_owner: MultiLocation,
unlocker: Location,
asset: Asset,
_owner: Location,
) -> Result<TestUnlockTicket, LockError> {
Ok(TestUnlockTicket(unlocker, asset))
}
fn note_unlockable(
_locker: MultiLocation,
_asset: MultiAsset,
_owner: MultiLocation,
_locker: Location,
_asset: Asset,
_owner: Location,
) -> Result<(), LockError> {
Ok(())
}
fn prepare_reduce_unlockable(
_locker: MultiLocation,
_asset: MultiAsset,
_owner: MultiLocation,
_locker: Location,
_asset: Asset,
_owner: Location,
) -> Result<TestReduceTicket, LockError> {
Ok(TestReduceTicket)
}
+12 -7
View File
@@ -66,20 +66,25 @@ fn alias_origin_should_work() {
]);
let message = Xcm(vec![AliasOrigin((AccountId32 { network: None, id: [0; 32] }).into())]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
(Parachain(1), AccountId32 { network: None, id: [0; 32] }),
message.clone(),
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete { used: Weight::from_parts(10, 10), error: XcmError::NoPermission }
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(10, 10), XcmError::NoPermission));
let r = XcmExecutor::<TestConfig>::execute_xcm(
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
(Parent, Parachain(1), AccountId32 { network: None, id: [0; 32] }),
message.clone(),
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(10, 10)));
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(10, 10) });
}
+215 -143
View File
@@ -32,10 +32,15 @@ fn exchange_asset_should_work() {
maximal: true,
},
]);
let hash = fake_message_hash(&message);
let r =
XcmExecutor::<TestConfig>::execute_xcm(Parent, message, hash, Weight::from_parts(50, 50));
assert_eq!(r, Outcome::Complete(Weight::from_parts(40, 40)));
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parent,
message,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(40, 40) });
assert_eq!(asset_list(Parent), vec![(Here, 100u128).into(), (Parent, 950u128).into()]);
assert_eq!(exchange_assets(), vec![(Parent, 50u128).into()].into());
}
@@ -56,10 +61,15 @@ fn exchange_asset_without_maximal_should_work() {
maximal: false,
},
]);
let hash = fake_message_hash(&message);
let r =
XcmExecutor::<TestConfig>::execute_xcm(Parent, message, hash, Weight::from_parts(50, 50));
assert_eq!(r, Outcome::Complete(Weight::from_parts(40, 40)));
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parent,
message,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(40, 40) });
assert_eq!(asset_list(Parent), vec![(Here, 50u128).into(), (Parent, 950u128).into()]);
assert_eq!(exchange_assets(), vec![(Here, 50u128).into(), (Parent, 50u128).into()].into());
}
@@ -80,10 +90,18 @@ fn exchange_asset_should_fail_when_no_deal_possible() {
maximal: false,
},
]);
let hash = fake_message_hash(&message);
let r =
XcmExecutor::<TestConfig>::execute_xcm(Parent, message, hash, Weight::from_parts(50, 50));
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(40, 40), XcmError::NoDeal));
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parent,
message,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete { used: Weight::from_parts(40, 40), error: XcmError::NoDeal }
);
assert_eq!(asset_list(Parent), vec![(Parent, 1000u128).into()]);
assert_eq!(exchange_assets(), vec![(Here, 100u128).into()].into());
}
@@ -100,32 +118,39 @@ fn paying_reserve_deposit_should_work() {
BuyExecution { fees, weight_limit: Limited(Weight::from_parts(30, 30)) },
DepositAsset { assets: AllCounted(1).into(), beneficiary: Here.into() },
]);
let hash = fake_message_hash(&message);
let mut hash = fake_message_hash(&message);
let weight_limit = Weight::from_parts(50, 50);
let r = XcmExecutor::<TestConfig>::execute_xcm(Parent, message, hash, weight_limit);
assert_eq!(r, Outcome::Complete(Weight::from_parts(30, 30)));
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parent,
message,
&mut hash,
weight_limit,
Weight::zero(),
);
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(30, 30) });
assert_eq!(asset_list(Here), vec![(Parent, 40u128).into()]);
}
#[test]
fn transfer_should_work() {
// we'll let them have message execution for free.
AllowUnpaidFrom::set(vec![X1(Parachain(1)).into()]);
AllowUnpaidFrom::set(vec![[Parachain(1)].into()]);
// Child parachain #1 owns 1000 tokens held by us in reserve.
add_asset(Parachain(1), (Here, 1000));
// They want to transfer 100 of them to their sibling parachain #2
let message = Xcm(vec![TransferAsset {
assets: (Here, 100u128).into(),
beneficiary: X1(AccountIndex64 { index: 3, network: None }).into(),
beneficiary: [AccountIndex64 { index: 3, network: None }].into(),
}]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(10, 10)));
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(10, 10) });
assert_eq!(
asset_list(AccountIndex64 { index: 3, network: None }),
vec![(Here, 100u128).into()]
@@ -136,27 +161,31 @@ fn transfer_should_work() {
#[test]
fn reserve_transfer_should_work() {
AllowUnpaidFrom::set(vec![X1(Parachain(1)).into()]);
AllowUnpaidFrom::set(vec![[Parachain(1)].into()]);
// Child parachain #1 owns 1000 tokens held by us in reserve.
add_asset(Parachain(1), (Here, 1000));
// The remote account owned by gav.
let three: MultiLocation = X1(AccountIndex64 { index: 3, network: None }).into();
let three: Location = [AccountIndex64 { index: 3, network: None }].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 message = Xcm(vec![TransferReserveAsset {
assets: (Here, 100u128).into(),
dest: Parachain(2).into(),
xcm: Xcm::<()>(vec![DepositAsset { assets: AllCounted(1).into(), beneficiary: three }]),
xcm: Xcm::<()>(vec![DepositAsset {
assets: AllCounted(1).into(),
beneficiary: three.clone(),
}]),
}]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(10, 10)));
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(10, 10) });
let expected_msg = Xcm::<()>(vec![
ReserveAssetDeposited((Parent, 100u128).into()),
@@ -171,7 +200,7 @@ fn reserve_transfer_should_work() {
#[test]
fn burn_should_work() {
// we'll let them have message execution for free.
AllowUnpaidFrom::set(vec![X1(Parachain(1)).into()]);
AllowUnpaidFrom::set(vec![[Parachain(1)].into()]);
// Child parachain #1 owns 1000 tokens held by us in reserve.
add_asset(Parachain(1), (Here, 1000));
// They want to burn 100 of them
@@ -180,14 +209,15 @@ fn burn_should_work() {
BurnAsset((Here, 100u128).into()),
DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Parachain(1).into() },
]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(30, 30)));
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(30, 30) });
assert_eq!(asset_list(Parachain(1)), vec![(Here, 900u128).into()]);
assert_eq!(sent_xcm(), vec![]);
@@ -197,14 +227,15 @@ fn burn_should_work() {
BurnAsset((Here, 1000u128).into()),
DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Parachain(1).into() },
]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(30, 30)));
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(30, 30) });
assert_eq!(asset_list(Parachain(1)), vec![]);
assert_eq!(sent_xcm(), vec![]);
}
@@ -212,7 +243,7 @@ fn burn_should_work() {
#[test]
fn basic_asset_trap_should_work() {
// we'll let them have message execution for free.
AllowUnpaidFrom::set(vec![X1(Parachain(1)).into(), X1(Parachain(2)).into()]);
AllowUnpaidFrom::set(vec![[Parachain(1)].into(), [Parachain(2)].into()]);
// Child parachain #1 owns 1000 tokens held by us in reserve.
add_asset(Parachain(1), (Here, 1000));
@@ -224,14 +255,15 @@ fn basic_asset_trap_should_work() {
beneficiary: AccountIndex64 { index: 3, network: None }.into(),
},
]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(20, 20),
Weight::zero(),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(25, 25)));
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(25, 25) });
assert_eq!(asset_list(Parachain(1)), vec![(Here, 900u128).into()]);
assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![]);
@@ -243,15 +275,19 @@ fn basic_asset_trap_should_work() {
beneficiary: AccountIndex64 { index: 3, network: None }.into(),
},
]);
let hash = fake_message_hash(&message);
let mut hash = fake_message_hash(&message);
let old_trapped_assets = TrappedAssets::get();
let r = XcmExecutor::<TestConfig>::execute_xcm(
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(20, 20),
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete { used: Weight::from_parts(10, 10), error: XcmError::UnknownClaim }
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(10, 10), XcmError::UnknownClaim));
assert_eq!(asset_list(Parachain(1)), vec![(Here, 900u128).into()]);
assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![]);
assert_eq!(old_trapped_assets, TrappedAssets::get());
@@ -264,15 +300,19 @@ fn basic_asset_trap_should_work() {
beneficiary: AccountIndex64 { index: 3, network: None }.into(),
},
]);
let hash = fake_message_hash(&message);
let mut hash = fake_message_hash(&message);
let old_trapped_assets = TrappedAssets::get();
let r = XcmExecutor::<TestConfig>::execute_xcm(
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(2),
message,
hash,
&mut hash,
Weight::from_parts(20, 20),
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete { used: Weight::from_parts(10, 10), error: XcmError::UnknownClaim }
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(10, 10), XcmError::UnknownClaim));
assert_eq!(asset_list(Parachain(1)), vec![(Here, 900u128).into()]);
assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![]);
assert_eq!(old_trapped_assets, TrappedAssets::get());
@@ -285,15 +325,19 @@ fn basic_asset_trap_should_work() {
beneficiary: AccountIndex64 { index: 3, network: None }.into(),
},
]);
let hash = fake_message_hash(&message);
let mut hash = fake_message_hash(&message);
let old_trapped_assets = TrappedAssets::get();
let r = XcmExecutor::<TestConfig>::execute_xcm(
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(20, 20),
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete { used: Weight::from_parts(10, 10), error: XcmError::UnknownClaim }
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(10, 10), XcmError::UnknownClaim));
assert_eq!(asset_list(Parachain(1)), vec![(Here, 900u128).into()]);
assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![]);
assert_eq!(old_trapped_assets, TrappedAssets::get());
@@ -305,14 +349,15 @@ fn basic_asset_trap_should_work() {
beneficiary: AccountIndex64 { index: 3, network: None }.into(),
},
]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(20, 20),
Weight::zero(),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(20, 20)));
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(20, 20) });
assert_eq!(asset_list(Parachain(1)), vec![(Here, 900u128).into()]);
assert_eq!(
asset_list(AccountIndex64 { index: 3, network: None }),
@@ -327,141 +372,168 @@ fn basic_asset_trap_should_work() {
beneficiary: AccountIndex64 { index: 3, network: None }.into(),
},
]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(20, 20),
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete { used: Weight::from_parts(10, 10), error: XcmError::UnknownClaim }
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(10, 10), XcmError::UnknownClaim));
}
#[test]
fn max_assets_limit_should_work() {
// we'll let them have message execution for free.
AllowUnpaidFrom::set(vec![X1(Parachain(1)).into()]);
AllowUnpaidFrom::set(vec![[Parachain(1)].into()]);
// Child parachain #1 owns 1000 tokens held by us in reserve.
add_asset(Parachain(1), ([1u8; 32], 1000u128));
add_asset(Parachain(1), ([2u8; 32], 1000u128));
add_asset(Parachain(1), ([3u8; 32], 1000u128));
add_asset(Parachain(1), ([4u8; 32], 1000u128));
add_asset(Parachain(1), ([5u8; 32], 1000u128));
add_asset(Parachain(1), ([6u8; 32], 1000u128));
add_asset(Parachain(1), ([7u8; 32], 1000u128));
add_asset(Parachain(1), ([8u8; 32], 1000u128));
add_asset(Parachain(1), ([9u8; 32], 1000u128));
add_asset(Parachain(1), (Junctions::from([GeneralIndex(0)]), 1000u128));
add_asset(Parachain(1), (Junctions::from([GeneralIndex(1)]), 1000u128));
add_asset(Parachain(1), (Junctions::from([GeneralIndex(2)]), 1000u128));
add_asset(Parachain(1), (Junctions::from([GeneralIndex(3)]), 1000u128));
add_asset(Parachain(1), (Junctions::from([GeneralIndex(4)]), 1000u128));
add_asset(Parachain(1), (Junctions::from([GeneralIndex(5)]), 1000u128));
add_asset(Parachain(1), (Junctions::from([GeneralIndex(6)]), 1000u128));
add_asset(Parachain(1), (Junctions::from([GeneralIndex(7)]), 1000u128));
add_asset(Parachain(1), (Junctions::from([GeneralIndex(8)]), 1000u128));
// Attempt to withdraw 8 (=2x4)different assets. This will succeed.
let message = Xcm(vec![
WithdrawAsset(([1u8; 32], 100u128).into()),
WithdrawAsset(([2u8; 32], 100u128).into()),
WithdrawAsset(([3u8; 32], 100u128).into()),
WithdrawAsset(([4u8; 32], 100u128).into()),
WithdrawAsset(([5u8; 32], 100u128).into()),
WithdrawAsset(([6u8; 32], 100u128).into()),
WithdrawAsset(([7u8; 32], 100u128).into()),
WithdrawAsset(([8u8; 32], 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(0)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(1)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(2)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(3)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(4)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(5)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(6)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(7)]), 100u128).into()),
]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(100, 100),
Weight::zero(),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(85, 85)));
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(85, 85) });
// Attempt to withdraw 9 different assets will fail.
let message = Xcm(vec![
WithdrawAsset(([1u8; 32], 100u128).into()),
WithdrawAsset(([2u8; 32], 100u128).into()),
WithdrawAsset(([3u8; 32], 100u128).into()),
WithdrawAsset(([4u8; 32], 100u128).into()),
WithdrawAsset(([5u8; 32], 100u128).into()),
WithdrawAsset(([6u8; 32], 100u128).into()),
WithdrawAsset(([7u8; 32], 100u128).into()),
WithdrawAsset(([8u8; 32], 100u128).into()),
WithdrawAsset(([9u8; 32], 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(0)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(1)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(2)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(3)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(4)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(5)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(6)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(7)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(8)]), 100u128).into()),
]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(100, 100),
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete {
used: Weight::from_parts(95, 95),
error: XcmError::HoldingWouldOverflow
}
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(95, 95), XcmError::HoldingWouldOverflow));
// Attempt to withdraw 4 different assets and then the same 4 and then a different 4 will
// succeed.
let message = Xcm(vec![
WithdrawAsset(([1u8; 32], 100u128).into()),
WithdrawAsset(([2u8; 32], 100u128).into()),
WithdrawAsset(([3u8; 32], 100u128).into()),
WithdrawAsset(([4u8; 32], 100u128).into()),
WithdrawAsset(([1u8; 32], 100u128).into()),
WithdrawAsset(([2u8; 32], 100u128).into()),
WithdrawAsset(([3u8; 32], 100u128).into()),
WithdrawAsset(([4u8; 32], 100u128).into()),
WithdrawAsset(([5u8; 32], 100u128).into()),
WithdrawAsset(([6u8; 32], 100u128).into()),
WithdrawAsset(([7u8; 32], 100u128).into()),
WithdrawAsset(([8u8; 32], 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(0)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(1)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(2)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(3)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(0)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(1)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(2)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(3)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(4)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(5)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(6)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(7)]), 100u128).into()),
]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(200, 200),
Weight::zero(),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(125, 125)));
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(125, 125) });
// Attempt to withdraw 4 different assets and then a different 4 and then the same 4 will fail.
let message = Xcm(vec![
WithdrawAsset(([1u8; 32], 100u128).into()),
WithdrawAsset(([2u8; 32], 100u128).into()),
WithdrawAsset(([3u8; 32], 100u128).into()),
WithdrawAsset(([4u8; 32], 100u128).into()),
WithdrawAsset(([5u8; 32], 100u128).into()),
WithdrawAsset(([6u8; 32], 100u128).into()),
WithdrawAsset(([7u8; 32], 100u128).into()),
WithdrawAsset(([8u8; 32], 100u128).into()),
WithdrawAsset(([1u8; 32], 100u128).into()),
WithdrawAsset(([2u8; 32], 100u128).into()),
WithdrawAsset(([3u8; 32], 100u128).into()),
WithdrawAsset(([4u8; 32], 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(0)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(1)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(2)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(3)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(4)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(5)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(6)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(7)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(0)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(1)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(2)]), 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(3)]), 100u128).into()),
]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(200, 200),
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete {
used: Weight::from_parts(95, 95),
error: XcmError::HoldingWouldOverflow
}
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(95, 95), XcmError::HoldingWouldOverflow));
// Attempt to withdraw 4 different assets and then a different 4 and then the same 4 will fail.
let message = Xcm(vec![
WithdrawAsset(MultiAssets::from(vec![
([1u8; 32], 100u128).into(),
([2u8; 32], 100u128).into(),
([3u8; 32], 100u128).into(),
([4u8; 32], 100u128).into(),
([5u8; 32], 100u128).into(),
([6u8; 32], 100u128).into(),
([7u8; 32], 100u128).into(),
([8u8; 32], 100u128).into(),
WithdrawAsset(Assets::from(vec![
(Junctions::from([GeneralIndex(0)]), 100u128).into(),
(Junctions::from([GeneralIndex(1)]), 100u128).into(),
(Junctions::from([GeneralIndex(2)]), 100u128).into(),
(Junctions::from([GeneralIndex(3)]), 100u128).into(),
(Junctions::from([GeneralIndex(4)]), 100u128).into(),
(Junctions::from([GeneralIndex(5)]), 100u128).into(),
(Junctions::from([GeneralIndex(6)]), 100u128).into(),
(Junctions::from([GeneralIndex(7)]), 100u128).into(),
])),
WithdrawAsset(([1u8; 32], 100u128).into()),
WithdrawAsset((Junctions::from([GeneralIndex(0)]), 100u128).into()),
]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(200, 200),
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete {
used: Weight::from_parts(25, 25),
error: XcmError::HoldingWouldOverflow
}
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(25, 25), XcmError::HoldingWouldOverflow));
}
+23 -17
View File
@@ -27,14 +27,8 @@ fn basic_setup_works() {
assert_eq!(to_account(Parachain(50)), Ok(1050));
assert_eq!(to_account((Parent, Parachain(1))), Ok(2001));
assert_eq!(to_account((Parent, Parachain(50))), Ok(2050));
assert_eq!(
to_account(MultiLocation::new(0, X1(AccountIndex64 { index: 1, network: None }))),
Ok(1),
);
assert_eq!(
to_account(MultiLocation::new(0, X1(AccountIndex64 { index: 42, network: None }))),
Ok(42),
);
assert_eq!(to_account(Location::new(0, [AccountIndex64 { index: 1, network: None }])), Ok(1),);
assert_eq!(to_account(Location::new(0, [AccountIndex64 { index: 42, network: None }])), Ok(42),);
assert_eq!(to_account(Here), Ok(3000));
}
@@ -65,7 +59,7 @@ fn code_registers_should_work() {
SetErrorHandler(Xcm(vec![
TransferAsset {
assets: (Here, 2u128).into(),
beneficiary: X1(AccountIndex64 { index: 3, network: None }).into(),
beneficiary: [AccountIndex64 { index: 3, network: None }].into(),
},
// It was handled fine.
ClearError,
@@ -73,33 +67,45 @@ fn code_registers_should_work() {
// Set the appendix - this will always fire.
SetAppendix(Xcm(vec![TransferAsset {
assets: (Here, 4u128).into(),
beneficiary: X1(AccountIndex64 { index: 3, network: None }).into(),
beneficiary: [AccountIndex64 { index: 3, network: None }].into(),
}])),
// First xfer always works ok
TransferAsset {
assets: (Here, 1u128).into(),
beneficiary: X1(AccountIndex64 { index: 3, network: None }).into(),
beneficiary: [AccountIndex64 { index: 3, network: None }].into(),
},
// Second xfer results in error on the second message - our error handler will fire.
TransferAsset {
assets: (Here, 8u128).into(),
beneficiary: X1(AccountIndex64 { index: 3, network: None }).into(),
beneficiary: [AccountIndex64 { index: 3, network: None }].into(),
},
]);
// Weight limit of 70 is needed.
let limit = <TestConfig as Config>::Weigher::weight(&mut message).unwrap();
assert_eq!(limit, Weight::from_parts(70, 70));
let hash = fake_message_hash(&message);
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(Here, message.clone(), hash, limit);
assert_eq!(r, Outcome::Complete(Weight::from_parts(50, 50))); // We don't pay the 20 weight for the error handler.
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Here,
message.clone(),
&mut hash,
limit,
Weight::zero(),
);
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(50, 50) }); // We don't pay the 20 weight for the error handler.
assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![(Here, 13u128).into()]);
assert_eq!(asset_list(Here), vec![(Here, 8u128).into()]);
assert_eq!(sent_xcm(), vec![]);
let r = XcmExecutor::<TestConfig>::execute_xcm(Here, message, hash, limit);
assert_eq!(r, Outcome::Complete(Weight::from_parts(70, 70))); // We pay the full weight here.
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Here,
message,
&mut hash,
limit,
Weight::zero(),
);
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(70, 70) }); // We pay the full weight here.
assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![(Here, 20u128).into()]);
assert_eq!(asset_list(Here), vec![(Here, 1u128).into()]);
assert_eq!(sent_xcm(), vec![]);
@@ -21,9 +21,9 @@
use super::*;
parameter_types! {
pub UniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1));
pub RemoteUniversalLocation: Junctions = X2(GlobalConsensus(Remote::get()), Parachain(1));
pub RemoteNetwork: MultiLocation = AncestorThen(2, GlobalConsensus(Remote::get())).into();
pub UniversalLocation: Junctions = [GlobalConsensus(Local::get()), Parachain(1)].into();
pub RemoteUniversalLocation: Junctions = [GlobalConsensus(Remote::get()), Parachain(1)].into();
pub RemoteNetwork: Location = AncestorThen(2, GlobalConsensus(Remote::get())).into();
}
type TheBridge =
TestBridge<BridgeBlobDispatcher<TestRemoteIncomingRouter, RemoteUniversalLocation, ()>>;
@@ -21,9 +21,9 @@
use super::*;
parameter_types! {
pub UniversalLocation: Junctions = X1(GlobalConsensus(Local::get()));
pub RemoteUniversalLocation: Junctions = X1(GlobalConsensus(Remote::get()));
pub RemoteNetwork: MultiLocation = AncestorThen(1, GlobalConsensus(Remote::get())).into();
pub UniversalLocation: Junctions = [GlobalConsensus(Local::get())].into();
pub RemoteUniversalLocation: Junctions = [GlobalConsensus(Remote::get())].into();
pub RemoteNetwork: Location = AncestorThen(1, GlobalConsensus(Remote::get())).into();
}
type TheBridge =
TestBridge<BridgeBlobDispatcher<TestRemoteIncomingRouter, RemoteUniversalLocation, ()>>;
@@ -37,7 +37,7 @@ mod remote_relay_relay;
parameter_types! {
pub Local: NetworkId = ByGenesis([0; 32]);
pub Remote: NetworkId = ByGenesis([1; 32]);
pub Price: MultiAssets = MultiAssets::from((Here, 100u128));
pub Price: Assets = Assets::from((Here, 100u128));
pub static UsingTopic: bool = false;
}
@@ -92,7 +92,7 @@ impl<R: SendXcm> SendXcm for TestTopic<R> {
}
}
fn validate(
destination: &mut Option<MultiLocation>,
destination: &mut Option<Location>,
message: &mut Option<Xcm<()>>,
) -> SendResult<Self::Ticket> {
Ok(if UsingTopic::get() {
@@ -120,26 +120,26 @@ impl<D: DispatchBlob> HaulBlob for TestBridge<D> {
}
std::thread_local! {
static REMOTE_INCOMING_XCM: RefCell<Vec<(MultiLocation, Xcm<()>)>> = RefCell::new(Vec::new());
static REMOTE_INCOMING_XCM: RefCell<Vec<(Location, Xcm<()>)>> = RefCell::new(Vec::new());
}
struct TestRemoteIncomingRouter;
impl SendXcm for TestRemoteIncomingRouter {
type Ticket = (MultiLocation, Xcm<()>);
type Ticket = (Location, Xcm<()>);
fn validate(
dest: &mut Option<MultiLocation>,
dest: &mut Option<Location>,
msg: &mut Option<Xcm<()>>,
) -> SendResult<(MultiLocation, Xcm<()>)> {
) -> SendResult<(Location, Xcm<()>)> {
let pair = (dest.take().unwrap(), msg.take().unwrap());
Ok((pair, MultiAssets::new()))
Ok((pair, Assets::new()))
}
fn deliver(pair: (MultiLocation, Xcm<()>)) -> Result<XcmHash, SendError> {
fn deliver(pair: (Location, Xcm<()>)) -> Result<XcmHash, SendError> {
let hash = fake_id();
REMOTE_INCOMING_XCM.with(|q| q.borrow_mut().push(pair));
Ok(hash)
}
}
fn take_received_remote_messages() -> Vec<(MultiLocation, Xcm<()>)> {
fn take_received_remote_messages() -> Vec<(Location, Xcm<()>)> {
REMOTE_INCOMING_XCM.with(|r| r.replace(vec![]))
}
@@ -152,18 +152,18 @@ struct UnpaidExecutingRouter<Local, Remote, RemoteExporter>(
fn price<RemoteExporter: ExportXcm>(
n: NetworkId,
c: u32,
s: &InteriorMultiLocation,
d: &InteriorMultiLocation,
s: &InteriorLocation,
d: &InteriorLocation,
m: &Xcm<()>,
) -> Result<MultiAssets, SendError> {
Ok(validate_export::<RemoteExporter>(n, c, *s, *d, m.clone())?.1)
) -> Result<Assets, SendError> {
Ok(validate_export::<RemoteExporter>(n, c, s.clone(), d.clone(), m.clone())?.1)
}
fn deliver<RemoteExporter: ExportXcm>(
n: NetworkId,
c: u32,
s: InteriorMultiLocation,
d: InteriorMultiLocation,
s: InteriorLocation,
d: InteriorLocation,
m: Xcm<()>,
) -> Result<XcmHash, SendError> {
export_xcm::<RemoteExporter>(n, c, s, d, m).map(|(hash, _)| hash)
@@ -189,7 +189,7 @@ impl<Local: Get<Junctions>, Remote: Get<Junctions>, RemoteExporter: ExportXcm> S
type Ticket = Xcm<()>;
fn validate(
destination: &mut Option<MultiLocation>,
destination: &mut Option<Location>,
message: &mut Option<Xcm<()>>,
) -> SendResult<Xcm<()>> {
let expect_dest = Remote::get().relative_to(&Local::get());
@@ -197,7 +197,7 @@ impl<Local: Get<Junctions>, Remote: Get<Junctions>, RemoteExporter: ExportXcm> S
return Err(NotApplicable)
}
let message = message.take().ok_or(MissingArgument)?;
Ok((message, MultiAssets::new()))
Ok((message, Assets::new()))
}
fn deliver(message: Xcm<()>) -> Result<XcmHash, SendError> {
@@ -206,7 +206,7 @@ impl<Local: Get<Junctions>, Remote: Get<Junctions>, RemoteExporter: ExportXcm> S
// though it is `Remote`.
ExecutorUniversalLocation::set(Remote::get());
let origin = Local::get().relative_to(&Remote::get());
AllowUnpaidFrom::set(vec![origin]);
AllowUnpaidFrom::set(vec![origin.clone()]);
set_exporter_override(price::<RemoteExporter>, deliver::<RemoteExporter>);
// The we execute it:
let mut id = fake_id();
@@ -222,9 +222,9 @@ impl<Local: Get<Junctions>, Remote: Get<Junctions>, RemoteExporter: ExportXcm> S
let entry = LogEntry { local, remote, id, message, outcome: outcome.clone(), paid: false };
RoutingLog::mutate(|l| l.push(entry));
match outcome {
Outcome::Complete(..) => Ok(id),
Outcome::Incomplete(..) => Err(Transport("Error executing")),
Outcome::Error(..) => Err(Transport("Unable to execute")),
Outcome::Complete { .. } => Ok(id),
Outcome::Incomplete { .. } => Err(Transport("Error executing")),
Outcome::Error { .. } => Err(Transport("Unable to execute")),
}
}
}
@@ -239,7 +239,7 @@ impl<Local: Get<Junctions>, Remote: Get<Junctions>, RemoteExporter: ExportXcm> S
type Ticket = Xcm<()>;
fn validate(
destination: &mut Option<MultiLocation>,
destination: &mut Option<Location>,
message: &mut Option<Xcm<()>>,
) -> SendResult<Xcm<()>> {
let expect_dest = Remote::get().relative_to(&Local::get());
@@ -247,7 +247,7 @@ impl<Local: Get<Junctions>, Remote: Get<Junctions>, RemoteExporter: ExportXcm> S
return Err(NotApplicable)
}
let message = message.take().ok_or(MissingArgument)?;
Ok((message, MultiAssets::new()))
Ok((message, Assets::new()))
}
fn deliver(message: Xcm<()>) -> Result<XcmHash, SendError> {
@@ -256,7 +256,7 @@ impl<Local: Get<Junctions>, Remote: Get<Junctions>, RemoteExporter: ExportXcm> S
// though it is `Remote`.
ExecutorUniversalLocation::set(Remote::get());
let origin = Local::get().relative_to(&Remote::get());
AllowPaidFrom::set(vec![origin]);
AllowPaidFrom::set(vec![origin.clone()]);
set_exporter_override(price::<RemoteExporter>, deliver::<RemoteExporter>);
// Then we execute it:
let mut id = fake_id();
@@ -272,9 +272,9 @@ impl<Local: Get<Junctions>, Remote: Get<Junctions>, RemoteExporter: ExportXcm> S
let entry = LogEntry { local, remote, id, message, outcome: outcome.clone(), paid: true };
RoutingLog::mutate(|l| l.push(entry));
match outcome {
Outcome::Complete(..) => Ok(id),
Outcome::Incomplete(..) => Err(Transport("Error executing")),
Outcome::Error(..) => Err(Transport("Unable to execute")),
Outcome::Complete { .. } => Ok(id),
Outcome::Incomplete { .. } => Err(Transport("Error executing")),
Outcome::Error { .. } => Err(Transport("Unable to execute")),
}
}
}
@@ -27,15 +27,15 @@ parameter_types! {
// 100 to use the bridge (export) and 80 for the remote execution weight (4 instructions x (10 +
// 10) weight each).
pub SendOverBridgePrice: u128 = 180u128 + if UsingTopic::get() { 20 } else { 0 };
pub UniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(100));
pub RelayUniversalLocation: Junctions = X1(GlobalConsensus(Local::get()));
pub RemoteUniversalLocation: Junctions = X1(GlobalConsensus(Remote::get()));
pub RemoteNetwork: MultiLocation = AncestorThen(1, GlobalConsensus(Remote::get())).into();
pub UniversalLocation: Junctions = [GlobalConsensus(Local::get()), Parachain(100)].into();
pub RelayUniversalLocation: Junctions = [GlobalConsensus(Local::get())].into();
pub RemoteUniversalLocation: Junctions = [GlobalConsensus(Remote::get())].into();
pub RemoteNetwork: Location = AncestorThen(1, GlobalConsensus(Remote::get())).into();
pub BridgeTable: Vec<NetworkExportTableItem> = vec![
NetworkExportTableItem::new(
Remote::get(),
None,
MultiLocation::parent(),
Location::parent(),
Some((Parent, SendOverBridgePrice::get()).into())
)
];
@@ -64,7 +64,7 @@ type LocalRouter = TestTopic<(LocalInnerRouter, LocalBridgeRouter)>;
#[test]
fn sending_to_bridged_chain_works() {
maybe_with_topic(|| {
let dest: MultiLocation = (Parent, Parent, Remote::get()).into();
let dest: Location = (Parent, Parent, Remote::get()).into();
// Initialize the local relay so that our parachain has funds to pay for export.
clear_assets(Parachain(100));
@@ -99,7 +99,7 @@ fn sending_to_bridged_chain_works() {
message: xcm_with_topic(
maybe_forward_id_for(&[0; 32]),
vec![
WithdrawAsset(MultiAsset::from((Here, price)).into()),
WithdrawAsset(Asset::from((Here, price)).into()),
BuyExecution { fees: (Here, price).into(), weight_limit: Unlimited },
ExportMessage {
network: ByGenesis([1; 32]),
@@ -109,7 +109,7 @@ fn sending_to_bridged_chain_works() {
DepositAsset { assets: Wild(All), beneficiary: Parachain(100).into() },
],
),
outcome: Outcome::Complete(test_weight(4)),
outcome: Outcome::Complete { used: test_weight(4) },
paid: true,
};
assert_eq!(RoutingLog::take(), vec![entry]);
@@ -117,7 +117,7 @@ fn sending_to_bridged_chain_works() {
}
#[test]
fn sending_to_bridged_chain_without_funds_fails() {
let dest: MultiLocation = (Parent, Parent, Remote::get()).into();
let dest: Location = (Parent, Parent, Remote::get()).into();
// Routing won't work if we don't have enough funds.
assert_eq!(
send_xcm::<LocalRouter>(dest, Xcm(vec![Trap(1)])),
@@ -138,7 +138,7 @@ fn sending_to_bridged_chain_without_funds_fails() {
#[test]
fn sending_to_parachain_of_bridged_chain_works() {
maybe_with_topic(|| {
let dest: MultiLocation = (Parent, Parent, Remote::get(), Parachain(100)).into();
let dest: Location = (Parent, Parent, Remote::get(), Parachain(100)).into();
// Initialize the local relay so that our parachain has funds to pay for export.
clear_assets(Parachain(100));
@@ -173,7 +173,7 @@ fn sending_to_parachain_of_bridged_chain_works() {
message: xcm_with_topic(
maybe_forward_id_for(&[0; 32]),
vec![
WithdrawAsset(MultiAsset::from((Here, price)).into()),
WithdrawAsset(Asset::from((Here, price)).into()),
BuyExecution { fees: (Here, price).into(), weight_limit: Unlimited },
ExportMessage {
network: ByGenesis([1; 32]),
@@ -183,7 +183,7 @@ fn sending_to_parachain_of_bridged_chain_works() {
DepositAsset { assets: Wild(All), beneficiary: Parachain(100).into() },
],
),
outcome: Outcome::Complete(test_weight(4)),
outcome: Outcome::Complete { used: test_weight(4) },
paid: true,
};
assert_eq!(RoutingLog::take(), vec![entry]);
@@ -191,7 +191,7 @@ fn sending_to_parachain_of_bridged_chain_works() {
}
#[test]
fn sending_to_parachain_of_bridged_chain_without_funds_fails() {
let dest: MultiLocation = (Parent, Parent, Remote::get(), Parachain(100)).into();
let dest: Location = (Parent, Parent, Remote::get(), Parachain(100)).into();
// Routing won't work if we don't have enough funds.
assert_eq!(
send_xcm::<LocalRouter>(dest, Xcm(vec![Trap(1)])),
@@ -21,10 +21,10 @@
use super::*;
parameter_types! {
pub UniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1000));
pub ParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1));
pub RemoteParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Remote::get()), Parachain(1));
pub RemoteNetwork: MultiLocation = AncestorThen(2, GlobalConsensus(Remote::get())).into();
pub UniversalLocation: Junctions = [GlobalConsensus(Local::get()), Parachain(1000)].into();
pub ParaBridgeUniversalLocation: Junctions = [GlobalConsensus(Local::get()), Parachain(1)].into();
pub RemoteParaBridgeUniversalLocation: Junctions = [GlobalConsensus(Remote::get()), Parachain(1)].into();
pub RemoteNetwork: Location = AncestorThen(2, GlobalConsensus(Remote::get())).into();
pub BridgeTable: Vec<NetworkExportTableItem> = vec![
NetworkExportTableItem::new(
Remote::get(),
@@ -62,7 +62,7 @@ fn sending_to_bridged_chain_works() {
send_xcm::<LocalRouter>((Parent, Parent, Remote::get(), Parachain(1)).into(), msg)
.unwrap()
.1,
MultiAssets::new()
Assets::new()
);
assert_eq!(TheBridge::service(), 1);
assert_eq!(
@@ -94,7 +94,7 @@ fn sending_to_bridged_chain_works() {
},
],
),
outcome: Outcome::Complete(test_weight(2)),
outcome: Outcome::Complete { used: test_weight(2) },
paid: false,
};
assert_eq!(RoutingLog::take(), vec![entry]);
@@ -116,7 +116,7 @@ fn sending_to_sibling_of_bridged_chain_works() {
maybe_with_topic(|| {
let msg = Xcm(vec![Trap(1)]);
let dest = (Parent, Parent, Remote::get(), Parachain(1000)).into();
assert_eq!(send_xcm::<LocalRouter>(dest, msg).unwrap().1, MultiAssets::new());
assert_eq!(send_xcm::<LocalRouter>(dest, msg).unwrap().1, Assets::new());
assert_eq!(TheBridge::service(), 1);
let expected = vec![(
(Parent, Parachain(1000)).into(),
@@ -145,7 +145,7 @@ fn sending_to_sibling_of_bridged_chain_works() {
},
],
),
outcome: Outcome::Complete(test_weight(2)),
outcome: Outcome::Complete { used: test_weight(2) },
paid: false,
};
assert_eq!(RoutingLog::take(), vec![entry]);
@@ -167,7 +167,7 @@ fn sending_to_relay_of_bridged_chain_works() {
maybe_with_topic(|| {
let msg = Xcm(vec![Trap(1)]);
let dest = (Parent, Parent, Remote::get()).into();
assert_eq!(send_xcm::<LocalRouter>(dest, msg).unwrap().1, MultiAssets::new());
assert_eq!(send_xcm::<LocalRouter>(dest, msg).unwrap().1, Assets::new());
assert_eq!(TheBridge::service(), 1);
let expected = vec![(
Parent.into(),
@@ -196,7 +196,7 @@ fn sending_to_relay_of_bridged_chain_works() {
},
],
),
outcome: Outcome::Complete(test_weight(2)),
outcome: Outcome::Complete { used: test_weight(2) },
paid: false,
};
assert_eq!(RoutingLog::take(), vec![entry]);
@@ -21,10 +21,10 @@
use super::*;
parameter_types! {
pub UniversalLocation: Junctions = X1(GlobalConsensus(Local::get()));
pub ParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1));
pub RemoteParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Remote::get()), Parachain(1));
pub RemoteNetwork: MultiLocation = AncestorThen(2, GlobalConsensus(Remote::get())).into();
pub UniversalLocation: Junctions = [GlobalConsensus(Local::get())].into();
pub ParaBridgeUniversalLocation: Junctions = [GlobalConsensus(Local::get()), Parachain(1)].into();
pub RemoteParaBridgeUniversalLocation: Junctions = [GlobalConsensus(Remote::get()), Parachain(1)].into();
pub RemoteNetwork: Location = AncestorThen(2, GlobalConsensus(Remote::get())).into();
pub BridgeTable: Vec<NetworkExportTableItem> = vec![
NetworkExportTableItem::new(
Remote::get(),
@@ -62,7 +62,7 @@ fn sending_to_bridged_chain_works() {
send_xcm::<LocalRouter>((Parent, Remote::get(), Parachain(1)).into(), msg)
.unwrap()
.1,
MultiAssets::new()
Assets::new()
);
assert_eq!(TheBridge::service(), 1);
let expected = vec![(
@@ -85,7 +85,7 @@ fn sending_to_bridged_chain_works() {
},
],
),
outcome: Outcome::Complete(test_weight(2)),
outcome: Outcome::Complete { used: test_weight(2) },
paid: false,
};
assert_eq!(RoutingLog::take(), vec![entry]);
@@ -107,7 +107,7 @@ fn sending_to_sibling_of_bridged_chain_works() {
maybe_with_topic(|| {
let msg = Xcm(vec![Trap(1)]);
let dest = (Parent, Remote::get(), Parachain(1000)).into();
assert_eq!(send_xcm::<LocalRouter>(dest, msg).unwrap().1, MultiAssets::new());
assert_eq!(send_xcm::<LocalRouter>(dest, msg).unwrap().1, Assets::new());
assert_eq!(TheBridge::service(), 1);
let expected = vec![(
(Parent, Parachain(1000)).into(),
@@ -129,7 +129,7 @@ fn sending_to_sibling_of_bridged_chain_works() {
},
],
),
outcome: Outcome::Complete(test_weight(2)),
outcome: Outcome::Complete { used: test_weight(2) },
paid: false,
};
assert_eq!(RoutingLog::take(), vec![entry]);
@@ -151,7 +151,7 @@ fn sending_to_relay_of_bridged_chain_works() {
maybe_with_topic(|| {
let msg = Xcm(vec![Trap(1)]);
let dest = (Parent, Remote::get()).into();
assert_eq!(send_xcm::<LocalRouter>(dest, msg).unwrap().1, MultiAssets::new());
assert_eq!(send_xcm::<LocalRouter>(dest, msg).unwrap().1, Assets::new());
assert_eq!(TheBridge::service(), 1);
let expected = vec![(
Parent.into(),
@@ -173,7 +173,7 @@ fn sending_to_relay_of_bridged_chain_works() {
},
],
),
outcome: Outcome::Complete(test_weight(2)),
outcome: Outcome::Complete { used: test_weight(2) },
paid: false,
};
assert_eq!(RoutingLog::take(), vec![entry]);
@@ -21,15 +21,15 @@
use super::*;
parameter_types! {
pub UniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1000));
pub RelayUniversalLocation: Junctions = X1(GlobalConsensus(Local::get()));
pub RemoteUniversalLocation: Junctions = X1(GlobalConsensus(Remote::get()));
pub RemoteNetwork: MultiLocation = AncestorThen(1, GlobalConsensus(Remote::get())).into();
pub UniversalLocation: Junctions = [GlobalConsensus(Local::get()), Parachain(1000)].into();
pub RelayUniversalLocation: Junctions = [GlobalConsensus(Local::get())].into();
pub RemoteUniversalLocation: Junctions = [GlobalConsensus(Remote::get())].into();
pub RemoteNetwork: Location = AncestorThen(1, GlobalConsensus(Remote::get())).into();
pub BridgeTable: Vec<NetworkExportTableItem> = vec![
NetworkExportTableItem::new(
Remote::get(),
None,
MultiLocation::parent(),
Location::parent(),
None
)
];
@@ -59,7 +59,7 @@ fn sending_to_bridged_chain_works() {
let msg = Xcm(vec![Trap(1)]);
assert_eq!(
send_xcm::<LocalRouter>((Parent, Parent, Remote::get()).into(), msg).unwrap().1,
MultiAssets::new()
Assets::new()
);
assert_eq!(TheBridge::service(), 1);
assert_eq!(
@@ -91,7 +91,7 @@ fn sending_to_bridged_chain_works() {
},
],
),
outcome: Outcome::Complete(test_weight(2)),
outcome: Outcome::Complete { used: test_weight(2) },
paid: false,
};
assert_eq!(RoutingLog::take(), vec![entry]);
@@ -113,7 +113,7 @@ fn sending_to_parachain_of_bridged_chain_works() {
maybe_with_topic(|| {
let msg = Xcm(vec![Trap(1)]);
let dest = (Parent, Parent, Remote::get(), Parachain(1000)).into();
assert_eq!(send_xcm::<LocalRouter>(dest, msg).unwrap().1, MultiAssets::new());
assert_eq!(send_xcm::<LocalRouter>(dest, msg).unwrap().1, Assets::new());
assert_eq!(TheBridge::service(), 1);
let expected = vec![(
Parachain(1000).into(),
@@ -142,7 +142,7 @@ fn sending_to_parachain_of_bridged_chain_works() {
},
],
),
outcome: Outcome::Complete(test_weight(2)),
outcome: Outcome::Complete { used: test_weight(2) },
paid: false,
};
assert_eq!(RoutingLog::take(), vec![entry]);
+88 -42
View File
@@ -18,7 +18,7 @@ use super::*;
#[test]
fn expect_pallet_should_work() {
AllowUnpaidFrom::set(vec![X1(Parachain(1)).into()]);
AllowUnpaidFrom::set(vec![[Parachain(1)].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 message = Xcm(vec![ExpectPallet {
@@ -28,14 +28,15 @@ fn expect_pallet_should_work() {
crate_major: 1,
min_crate_minor: 42,
}]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(10, 10)));
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(10, 10) });
let message = Xcm(vec![ExpectPallet {
index: 1,
@@ -44,19 +45,20 @@ fn expect_pallet_should_work() {
crate_major: 1,
min_crate_minor: 41,
}]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(10, 10)));
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(10, 10) });
}
#[test]
fn expect_pallet_should_fail_correctly() {
AllowUnpaidFrom::set(vec![X1(Parachain(1)).into()]);
AllowUnpaidFrom::set(vec![[Parachain(1)].into()]);
let message = Xcm(vec![ExpectPallet {
index: 1,
name: b"Balances".as_ref().into(),
@@ -64,14 +66,21 @@ fn expect_pallet_should_fail_correctly() {
crate_major: 1,
min_crate_minor: 60,
}]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete {
used: Weight::from_parts(10, 10),
error: XcmError::VersionIncompatible
}
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(10, 10), XcmError::VersionIncompatible));
let message = Xcm(vec![ExpectPallet {
index: 1,
@@ -80,14 +89,18 @@ fn expect_pallet_should_fail_correctly() {
crate_major: 1,
min_crate_minor: 42,
}]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete { used: Weight::from_parts(10, 10), error: XcmError::NameMismatch }
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(10, 10), XcmError::NameMismatch));
let message = Xcm(vec![ExpectPallet {
index: 1,
@@ -96,14 +109,18 @@ fn expect_pallet_should_fail_correctly() {
crate_major: 1,
min_crate_minor: 42,
}]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete { used: Weight::from_parts(10, 10), error: XcmError::NameMismatch }
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(10, 10), XcmError::NameMismatch));
let message = Xcm(vec![ExpectPallet {
index: 0,
@@ -112,14 +129,18 @@ fn expect_pallet_should_fail_correctly() {
crate_major: 1,
min_crate_minor: 42,
}]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete { used: Weight::from_parts(10, 10), error: XcmError::NameMismatch }
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(10, 10), XcmError::NameMismatch));
let message = Xcm(vec![ExpectPallet {
index: 2,
@@ -128,14 +149,18 @@ fn expect_pallet_should_fail_correctly() {
crate_major: 1,
min_crate_minor: 42,
}]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete { used: Weight::from_parts(10, 10), error: XcmError::PalletNotFound }
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(10, 10), XcmError::PalletNotFound));
let message = Xcm(vec![ExpectPallet {
index: 1,
@@ -144,14 +169,21 @@ fn expect_pallet_should_fail_correctly() {
crate_major: 2,
min_crate_minor: 42,
}]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete {
used: Weight::from_parts(10, 10),
error: XcmError::VersionIncompatible
}
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(10, 10), XcmError::VersionIncompatible));
let message = Xcm(vec![ExpectPallet {
index: 1,
@@ -160,14 +192,21 @@ fn expect_pallet_should_fail_correctly() {
crate_major: 0,
min_crate_minor: 42,
}]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete {
used: Weight::from_parts(10, 10),
error: XcmError::VersionIncompatible
}
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(10, 10), XcmError::VersionIncompatible));
let message = Xcm(vec![ExpectPallet {
index: 1,
@@ -176,12 +215,19 @@ fn expect_pallet_should_fail_correctly() {
crate_major: 1,
min_crate_minor: 43,
}]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete {
used: Weight::from_parts(10, 10),
error: XcmError::VersionIncompatible
}
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(10, 10), XcmError::VersionIncompatible));
}
+90 -40
View File
@@ -34,10 +34,15 @@ fn lock_roundtrip_should_work() {
),
LockAsset { asset: (Parent, 100u128).into(), unlocker: (Parent, Parachain(1)).into() },
]);
let hash = fake_message_hash(&message);
let r =
XcmExecutor::<TestConfig>::execute_xcm((3u64,), message, hash, Weight::from_parts(50, 50));
assert_eq!(r, Outcome::Complete(Weight::from_parts(40, 40)));
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
(3u64,),
message,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(40, 40) });
assert_eq!(asset_list((3u64,)), vec![(Parent, 990u128).into()]);
let expected_msg = Xcm::<()>(vec![NoteUnlockable {
@@ -58,14 +63,15 @@ fn lock_roundtrip_should_work() {
// Now we'll unlock it.
let message =
Xcm(vec![UnlockAsset { asset: (Parent, 100u128).into(), target: (3u64,).into() }]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
(Parent, Parachain(1)),
message,
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(10, 10)));
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(10, 10) });
}
#[test]
@@ -82,10 +88,15 @@ fn auto_fee_paying_should_work() {
SetFeesMode { jit_withdraw: true },
LockAsset { asset: (Parent, 100u128).into(), unlocker: (Parent, Parachain(1)).into() },
]);
let hash = fake_message_hash(&message);
let r =
XcmExecutor::<TestConfig>::execute_xcm((3u64,), message, hash, Weight::from_parts(50, 50));
assert_eq!(r, Outcome::Complete(Weight::from_parts(20, 20)));
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
(3u64,),
message,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(20, 20) });
assert_eq!(asset_list((3u64,)), vec![(Parent, 990u128).into()]);
}
@@ -100,10 +111,18 @@ fn lock_should_fail_correctly() {
asset: (Parent, 100u128).into(),
unlocker: (Parent, Parachain(1)).into(),
}]);
let hash = fake_message_hash(&message);
let r =
XcmExecutor::<TestConfig>::execute_xcm((3u64,), message, hash, Weight::from_parts(50, 50));
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(10, 10), XcmError::LockError));
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
(3u64,),
message,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete { used: Weight::from_parts(10, 10), error: XcmError::LockError }
);
assert_eq!(sent_xcm(), vec![]);
assert_eq!(take_lock_trace(), vec![]);
@@ -118,10 +137,18 @@ fn lock_should_fail_correctly() {
asset: (Parent, 100u128).into(),
unlocker: (Parent, Parachain(1)).into(),
}]);
let hash = fake_message_hash(&message);
let r =
XcmExecutor::<TestConfig>::execute_xcm((3u64,), message, hash, Weight::from_parts(50, 50));
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(10, 10), XcmError::NotHoldingFees));
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
(3u64,),
message,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete { used: Weight::from_parts(10, 10), error: XcmError::NotHoldingFees }
);
assert_eq!(sent_xcm(), vec![]);
assert_eq!(take_lock_trace(), vec![]);
}
@@ -140,14 +167,15 @@ fn remote_unlock_roundtrip_should_work() {
// This caused Parachain #1 to send us the NoteUnlockable instruction.
let message =
Xcm(vec![NoteUnlockable { asset: (Parent, 100u128).into(), owner: (3u64,).into() }]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
(Parent, Parachain(1)),
message,
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(10, 10)));
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(10, 10) });
assert_eq!(
take_lock_trace(),
vec![Note {
@@ -165,10 +193,15 @@ fn remote_unlock_roundtrip_should_work() {
),
RequestUnlock { asset: (Parent, 100u128).into(), locker: (Parent, Parachain(1)).into() },
]);
let hash = fake_message_hash(&message);
let r =
XcmExecutor::<TestConfig>::execute_xcm((3u64,), message, hash, Weight::from_parts(50, 50));
assert_eq!(r, Outcome::Complete(Weight::from_parts(40, 40)));
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
(3u64,),
message,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(40, 40) });
assert_eq!(asset_list((3u64,)), vec![(Parent, 990u128).into()]);
let expected_msg = Xcm::<()>(vec![UnlockAsset {
@@ -201,24 +234,33 @@ fn remote_unlock_should_fail_correctly() {
asset: (Parent, 100u128).into(),
locker: (Parent, Parachain(1)).into(),
}]);
let hash = fake_message_hash(&message);
let r =
XcmExecutor::<TestConfig>::execute_xcm((3u64,), message, hash, Weight::from_parts(50, 50));
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(10, 10), XcmError::LockError));
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
(3u64,),
message,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete { used: Weight::from_parts(10, 10), error: XcmError::LockError }
);
assert_eq!(sent_xcm(), vec![]);
assert_eq!(take_lock_trace(), vec![]);
// We have been told by Parachain #1 that Account #3 has locked funds which we can unlock.
let message =
Xcm(vec![NoteUnlockable { asset: (Parent, 100u128).into(), owner: (3u64,).into() }]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
(Parent, Parachain(1)),
message,
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(10, 10)));
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(10, 10) });
let _discard = take_lock_trace();
// We want to unlock 100 of the native parent tokens which were locked for us on parachain.
@@ -228,10 +270,18 @@ fn remote_unlock_should_fail_correctly() {
asset: (Parent, 100u128).into(),
locker: (Parent, Parachain(1)).into(),
}]);
let hash = fake_message_hash(&message);
let r =
XcmExecutor::<TestConfig>::execute_xcm((3u64,), message, hash, Weight::from_parts(50, 50));
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(10, 10), XcmError::NotHoldingFees));
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
(3u64,),
message,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete { used: Weight::from_parts(10, 10), error: XcmError::NotHoldingFees }
);
assert_eq!(sent_xcm(), vec![]);
assert_eq!(take_lock_trace(), vec![]);
+158 -157
View File
@@ -28,7 +28,7 @@ pub use crate::{
use frame_support::traits::{ContainsPair, Everything};
pub use frame_support::{
dispatch::{DispatchInfo, DispatchResultWithPostInfo, GetDispatchInfo, PostDispatchInfo},
ensure, match_types, parameter_types,
ensure, parameter_types,
sp_runtime::{traits::Dispatchable, DispatchError, DispatchErrorWithPostInfo},
traits::{Contains, Get, IsInVec},
};
@@ -45,7 +45,7 @@ pub use xcm_executor::{
AssetExchange, AssetLock, CheckSuspension, ConvertOrigin, Enact, ExportXcm, FeeManager,
FeeReason, LockError, OnResponse, TransactAsset,
},
Assets, Config,
AssetsInHolding, Config,
};
#[derive(Debug)]
@@ -110,52 +110,52 @@ impl GetDispatchInfo for TestCall {
}
thread_local! {
pub static SENT_XCM: RefCell<Vec<(MultiLocation, Xcm<()>, XcmHash)>> = RefCell::new(Vec::new());
pub static SENT_XCM: RefCell<Vec<(Location, Xcm<()>, XcmHash)>> = RefCell::new(Vec::new());
pub static EXPORTED_XCM: RefCell<
Vec<(NetworkId, u32, InteriorMultiLocation, InteriorMultiLocation, Xcm<()>, XcmHash)>
Vec<(NetworkId, u32, InteriorLocation, InteriorLocation, Xcm<()>, XcmHash)>
> = RefCell::new(Vec::new());
pub static EXPORTER_OVERRIDE: RefCell<Option<(
fn(
NetworkId,
u32,
&InteriorMultiLocation,
&InteriorMultiLocation,
&InteriorLocation,
&InteriorLocation,
&Xcm<()>,
) -> Result<MultiAssets, SendError>,
) -> Result<Assets, SendError>,
fn(
NetworkId,
u32,
InteriorMultiLocation,
InteriorMultiLocation,
InteriorLocation,
InteriorLocation,
Xcm<()>,
) -> Result<XcmHash, SendError>,
)>> = RefCell::new(None);
pub static SEND_PRICE: RefCell<MultiAssets> = RefCell::new(MultiAssets::new());
pub static SEND_PRICE: RefCell<Assets> = RefCell::new(Assets::new());
pub static SUSPENDED: Cell<bool> = Cell::new(false);
}
pub fn sent_xcm() -> Vec<(MultiLocation, opaque::Xcm, XcmHash)> {
pub fn sent_xcm() -> Vec<(Location, opaque::Xcm, XcmHash)> {
SENT_XCM.with(|q| (*q.borrow()).clone())
}
pub fn set_send_price(p: impl Into<MultiAsset>) {
pub fn set_send_price(p: impl Into<Asset>) {
SEND_PRICE.with(|l| l.replace(p.into().into()));
}
pub fn exported_xcm(
) -> Vec<(NetworkId, u32, InteriorMultiLocation, InteriorMultiLocation, opaque::Xcm, XcmHash)> {
) -> Vec<(NetworkId, u32, InteriorLocation, InteriorLocation, opaque::Xcm, XcmHash)> {
EXPORTED_XCM.with(|q| (*q.borrow()).clone())
}
pub fn set_exporter_override(
price: fn(
NetworkId,
u32,
&InteriorMultiLocation,
&InteriorMultiLocation,
&InteriorLocation,
&InteriorLocation,
&Xcm<()>,
) -> Result<MultiAssets, SendError>,
) -> Result<Assets, SendError>,
deliver: fn(
NetworkId,
u32,
InteriorMultiLocation,
InteriorMultiLocation,
InteriorLocation,
InteriorLocation,
Xcm<()>,
) -> Result<XcmHash, SendError>,
) {
@@ -167,17 +167,17 @@ pub fn clear_exporter_override() {
}
pub struct TestMessageSender;
impl SendXcm for TestMessageSender {
type Ticket = (MultiLocation, Xcm<()>, XcmHash);
type Ticket = (Location, Xcm<()>, XcmHash);
fn validate(
dest: &mut Option<MultiLocation>,
dest: &mut Option<Location>,
msg: &mut Option<Xcm<()>>,
) -> SendResult<(MultiLocation, Xcm<()>, XcmHash)> {
) -> SendResult<(Location, Xcm<()>, XcmHash)> {
let msg = msg.take().unwrap();
let hash = fake_message_hash(&msg);
let triplet = (dest.take().unwrap(), msg, hash);
Ok((triplet, SEND_PRICE.with(|l| l.borrow().clone())))
}
fn deliver(triplet: (MultiLocation, Xcm<()>, XcmHash)) -> Result<XcmHash, SendError> {
fn deliver(triplet: (Location, Xcm<()>, XcmHash)) -> Result<XcmHash, SendError> {
let hash = triplet.2;
SENT_XCM.with(|q| q.borrow_mut().push(triplet));
Ok(hash)
@@ -185,21 +185,20 @@ impl SendXcm for TestMessageSender {
}
pub struct TestMessageExporter;
impl ExportXcm for TestMessageExporter {
type Ticket = (NetworkId, u32, InteriorMultiLocation, InteriorMultiLocation, Xcm<()>, XcmHash);
type Ticket = (NetworkId, u32, InteriorLocation, InteriorLocation, Xcm<()>, XcmHash);
fn validate(
network: NetworkId,
channel: u32,
uni_src: &mut Option<InteriorMultiLocation>,
dest: &mut Option<InteriorMultiLocation>,
uni_src: &mut Option<InteriorLocation>,
dest: &mut Option<InteriorLocation>,
msg: &mut Option<Xcm<()>>,
) -> SendResult<(NetworkId, u32, InteriorMultiLocation, InteriorMultiLocation, Xcm<()>, XcmHash)>
{
) -> SendResult<(NetworkId, u32, InteriorLocation, InteriorLocation, Xcm<()>, XcmHash)> {
let (s, d, m) = (uni_src.take().unwrap(), dest.take().unwrap(), msg.take().unwrap());
let r: Result<MultiAssets, SendError> = EXPORTER_OVERRIDE.with(|e| {
let r: Result<Assets, SendError> = EXPORTER_OVERRIDE.with(|e| {
if let Some((ref f, _)) = &*e.borrow() {
f(network, channel, &s, &d, &m)
} else {
Ok(MultiAssets::new())
Ok(Assets::new())
}
});
let h = fake_message_hash(&m);
@@ -214,7 +213,7 @@ impl ExportXcm for TestMessageExporter {
}
}
fn deliver(
tuple: (NetworkId, u32, InteriorMultiLocation, InteriorMultiLocation, Xcm<()>, XcmHash),
tuple: (NetworkId, u32, InteriorLocation, InteriorLocation, Xcm<()>, XcmHash),
) -> Result<XcmHash, SendError> {
EXPORTER_OVERRIDE.with(|e| {
if let Some((_, ref f)) = &*e.borrow() {
@@ -230,37 +229,42 @@ impl ExportXcm for TestMessageExporter {
}
thread_local! {
pub static ASSETS: RefCell<BTreeMap<MultiLocation, Assets>> = RefCell::new(BTreeMap::new());
pub static ASSETS: RefCell<BTreeMap<Location, AssetsInHolding>> = RefCell::new(BTreeMap::new());
}
pub fn assets(who: impl Into<MultiLocation>) -> Assets {
pub fn assets(who: impl Into<Location>) -> AssetsInHolding {
ASSETS.with(|a| a.borrow().get(&who.into()).cloned()).unwrap_or_default()
}
pub fn asset_list(who: impl Into<MultiLocation>) -> Vec<MultiAsset> {
MultiAssets::from(assets(who)).into_inner()
pub fn asset_list(who: impl Into<Location>) -> Vec<Asset> {
Assets::from(assets(who)).into_inner()
}
pub fn add_asset(who: impl Into<MultiLocation>, what: impl Into<MultiAsset>) {
ASSETS.with(|a| a.borrow_mut().entry(who.into()).or_insert(Assets::new()).subsume(what.into()));
pub fn add_asset(who: impl Into<Location>, what: impl Into<Asset>) {
ASSETS.with(|a| {
a.borrow_mut()
.entry(who.into())
.or_insert(AssetsInHolding::new())
.subsume(what.into())
});
}
pub fn clear_assets(who: impl Into<MultiLocation>) {
pub fn clear_assets(who: impl Into<Location>) {
ASSETS.with(|a| a.borrow_mut().remove(&who.into()));
}
pub struct TestAssetTransactor;
impl TransactAsset for TestAssetTransactor {
fn deposit_asset(
what: &MultiAsset,
who: &MultiLocation,
what: &Asset,
who: &Location,
_context: Option<&XcmContext>,
) -> Result<(), XcmError> {
add_asset(*who, what.clone());
add_asset(who.clone(), what.clone());
Ok(())
}
fn withdraw_asset(
what: &MultiAsset,
who: &MultiLocation,
what: &Asset,
who: &Location,
_maybe_context: Option<&XcmContext>,
) -> Result<Assets, XcmError> {
) -> Result<AssetsInHolding, XcmError> {
ASSETS.with(|a| {
a.borrow_mut()
.get_mut(who)
@@ -271,19 +275,20 @@ impl TransactAsset for TestAssetTransactor {
}
}
pub fn to_account(l: impl Into<MultiLocation>) -> Result<u64, MultiLocation> {
Ok(match l.into() {
pub fn to_account(l: impl Into<Location>) -> Result<u64, Location> {
let l = l.into();
Ok(match l.unpack() {
// Siblings at 2000+id
MultiLocation { parents: 1, interior: X1(Parachain(id)) } => 2000 + id as u64,
(1, [Parachain(id)]) => 2000 + *id as u64,
// Accounts are their number
MultiLocation { parents: 0, interior: X1(AccountIndex64 { index, .. }) } => index,
(0, [AccountIndex64 { index, .. }]) => *index,
// Children at 1000+id
MultiLocation { parents: 0, interior: X1(Parachain(id)) } => 1000 + id as u64,
(0, [Parachain(id)]) => 1000 + *id as u64,
// Self at 3000
MultiLocation { parents: 0, interior: Here } => 3000,
(0, []) => 3000,
// Parent at 3001
MultiLocation { parents: 1, interior: Here } => 3001,
l => {
(1, []) => 3001,
_ => {
// Is it a foreign-consensus?
let uni = ExecutorUniversalLocation::get();
if l.parents as usize != uni.len() {
@@ -301,36 +306,35 @@ pub fn to_account(l: impl Into<MultiLocation>) -> Result<u64, MultiLocation> {
pub struct TestOriginConverter;
impl ConvertOrigin<TestOrigin> for TestOriginConverter {
fn convert_origin(
origin: impl Into<MultiLocation>,
origin: impl Into<Location>,
kind: OriginKind,
) -> Result<TestOrigin, MultiLocation> {
) -> Result<TestOrigin, Location> {
use OriginKind::*;
match (kind, origin.into()) {
let origin = origin.into();
match (kind, origin.unpack()) {
(Superuser, _) => Ok(TestOrigin::Root),
(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),
(Native, MultiLocation { parents: 0, interior: X1(AccountIndex64 { index, .. }) }) =>
Ok(TestOrigin::Signed(index)),
(_, origin) => Err(origin),
(SovereignAccount, _) => Ok(TestOrigin::Signed(to_account(origin)?)),
(Native, (0, [Parachain(id)])) => Ok(TestOrigin::Parachain(*id)),
(Native, (1, [])) => Ok(TestOrigin::Relay),
(Native, (0, [AccountIndex64 { index, .. }])) => Ok(TestOrigin::Signed(*index)),
_ => Err(origin),
}
}
}
thread_local! {
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 static UNIVERSAL_ALIASES: RefCell<BTreeSet<(MultiLocation, Junction)>> = RefCell::new(BTreeSet::new());
pub static IS_RESERVE: RefCell<BTreeMap<Location, Vec<AssetFilter>>> = RefCell::new(BTreeMap::new());
pub static IS_TELEPORTER: RefCell<BTreeMap<Location, Vec<AssetFilter>>> = RefCell::new(BTreeMap::new());
pub static UNIVERSAL_ALIASES: RefCell<BTreeSet<(Location, Junction)>> = RefCell::new(BTreeSet::new());
}
pub fn add_reserve(from: MultiLocation, asset: MultiAssetFilter) {
pub fn add_reserve(from: Location, asset: AssetFilter) {
IS_RESERVE.with(|r| r.borrow_mut().entry(from).or_default().push(asset));
}
#[allow(dead_code)]
pub fn add_teleporter(from: MultiLocation, asset: MultiAssetFilter) {
pub fn add_teleporter(from: Location, asset: AssetFilter) {
IS_TELEPORTER.with(|r| r.borrow_mut().entry(from).or_default().push(asset));
}
pub fn add_universal_alias(bridge: impl Into<MultiLocation>, consensus: impl Into<Junction>) {
pub fn add_universal_alias(bridge: impl Into<Location>, consensus: impl Into<Junction>) {
UNIVERSAL_ALIASES.with(|r| r.borrow_mut().insert((bridge.into(), consensus.into())));
}
pub fn clear_universal_aliases() {
@@ -338,29 +342,29 @@ pub fn clear_universal_aliases() {
}
pub struct TestIsReserve;
impl ContainsPair<MultiAsset, MultiLocation> for TestIsReserve {
fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool {
impl ContainsPair<Asset, Location> for TestIsReserve {
fn contains(asset: &Asset, origin: &Location) -> bool {
IS_RESERVE
.with(|r| r.borrow().get(origin).map_or(false, |v| v.iter().any(|a| a.matches(asset))))
}
}
pub struct TestIsTeleporter;
impl ContainsPair<MultiAsset, MultiLocation> for TestIsTeleporter {
fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool {
impl ContainsPair<Asset, Location> for TestIsTeleporter {
fn contains(asset: &Asset, origin: &Location) -> bool {
IS_TELEPORTER
.with(|r| r.borrow().get(origin).map_or(false, |v| v.iter().any(|a| a.matches(asset))))
}
}
pub struct TestUniversalAliases;
impl Contains<(MultiLocation, Junction)> for TestUniversalAliases {
fn contains(t: &(MultiLocation, Junction)) -> bool {
impl Contains<(Location, Junction)> for TestUniversalAliases {
fn contains(t: &(Location, Junction)) -> bool {
UNIVERSAL_ALIASES.with(|r| r.borrow().contains(t))
}
}
pub enum ResponseSlot {
Expecting(MultiLocation),
Expecting(Location),
Received(Response),
}
thread_local! {
@@ -368,20 +372,16 @@ thread_local! {
}
pub struct TestResponseHandler;
impl OnResponse for TestResponseHandler {
fn expecting_response(
origin: &MultiLocation,
query_id: u64,
_querier: Option<&MultiLocation>,
) -> bool {
fn expecting_response(origin: &Location, query_id: u64, _querier: Option<&Location>) -> bool {
QUERIES.with(|q| match q.borrow().get(&query_id) {
Some(ResponseSlot::Expecting(ref l)) => l == origin,
_ => false,
})
}
fn on_response(
_origin: &MultiLocation,
_origin: &Location,
query_id: u64,
_querier: Option<&MultiLocation>,
_querier: Option<&Location>,
response: xcm::latest::Response,
_max_weight: Weight,
_context: &XcmContext,
@@ -396,7 +396,7 @@ impl OnResponse for TestResponseHandler {
Weight::from_parts(10, 10)
}
}
pub fn expect_response(query_id: u64, from: MultiLocation) {
pub fn expect_response(query_id: u64, from: Location) {
QUERIES.with(|q| q.borrow_mut().insert(query_id, ResponseSlot::Expecting(from)));
}
pub fn response(query_id: u64) -> Option<Response> {
@@ -420,9 +420,9 @@ impl<T: Config, BlockNumber: sp_runtime::traits::Zero + Encode> QueryHandler
type UniversalLocation = T::UniversalLocation;
fn new_query(
responder: impl Into<MultiLocation>,
responder: impl Into<Location>,
_timeout: Self::BlockNumber,
_match_querier: impl Into<MultiLocation>,
_match_querier: impl Into<Location>,
) -> Self::QueryId {
let query_id = 1;
expect_response(query_id, responder.into());
@@ -431,7 +431,7 @@ impl<T: Config, BlockNumber: sp_runtime::traits::Zero + Encode> QueryHandler
fn report_outcome(
message: &mut Xcm<()>,
responder: impl Into<MultiLocation>,
responder: impl Into<Location>,
timeout: Self::BlockNumber,
) -> Result<Self::QueryId, Self::Error> {
let responder = responder.into();
@@ -466,16 +466,16 @@ impl<T: Config, BlockNumber: sp_runtime::traits::Zero + Encode> QueryHandler
}
parameter_types! {
pub static ExecutorUniversalLocation: InteriorMultiLocation
pub static ExecutorUniversalLocation: InteriorLocation
= (ByGenesis([0; 32]), Parachain(42)).into();
pub UnitWeightCost: Weight = Weight::from_parts(10, 10);
}
parameter_types! {
// Nothing is allowed to be paid/unpaid by default.
pub static AllowExplicitUnpaidFrom: Vec<MultiLocation> = vec![];
pub static AllowUnpaidFrom: Vec<MultiLocation> = vec![];
pub static AllowPaidFrom: Vec<MultiLocation> = vec![];
pub static AllowSubsFrom: Vec<MultiLocation> = vec![];
pub static AllowExplicitUnpaidFrom: Vec<Location> = vec![];
pub static AllowUnpaidFrom: Vec<Location> = vec![];
pub static AllowPaidFrom: Vec<Location> = vec![];
pub static AllowSubsFrom: Vec<Location> = vec![];
// 1_000_000_000_000 => 1 unit of asset for 1 unit of ref time weight.
// 1024 * 1024 => 1 unit of asset for 1 unit of proof size weight.
pub static WeightPrice: (AssetId, u128, u128) =
@@ -486,7 +486,7 @@ parameter_types! {
pub struct TestSuspender;
impl CheckSuspension for TestSuspender {
fn is_suspended<Call>(
_origin: &MultiLocation,
_origin: &Location,
_instructions: &mut [Instruction<Call>],
_max_weight: Weight,
_properties: &mut Properties,
@@ -520,34 +520,34 @@ pub fn set_fee_waiver(waived: Vec<FeeReason>) {
pub struct TestFeeManager;
impl FeeManager for TestFeeManager {
fn is_waived(_: Option<&MultiLocation>, r: FeeReason) -> bool {
fn is_waived(_: Option<&Location>, r: FeeReason) -> bool {
IS_WAIVED.with(|l| l.borrow().contains(&r))
}
fn handle_fee(_: MultiAssets, _: Option<&XcmContext>, _: FeeReason) {}
fn handle_fee(_: Assets, _: Option<&XcmContext>, _: FeeReason) {}
}
#[derive(Clone, Eq, PartialEq, Debug)]
pub enum LockTraceItem {
Lock { unlocker: MultiLocation, asset: MultiAsset, owner: MultiLocation },
Unlock { unlocker: MultiLocation, asset: MultiAsset, owner: MultiLocation },
Note { locker: MultiLocation, asset: MultiAsset, owner: MultiLocation },
Reduce { locker: MultiLocation, asset: MultiAsset, owner: MultiLocation },
Lock { unlocker: Location, asset: Asset, owner: Location },
Unlock { unlocker: Location, asset: Asset, owner: Location },
Note { locker: Location, asset: Asset, owner: Location },
Reduce { locker: Location, asset: Asset, owner: Location },
}
thread_local! {
pub static NEXT_INDEX: RefCell<u32> = RefCell::new(0);
pub static LOCK_TRACE: RefCell<Vec<LockTraceItem>> = RefCell::new(Vec::new());
pub static ALLOWED_UNLOCKS: RefCell<BTreeMap<(MultiLocation, MultiLocation), Assets>> = RefCell::new(BTreeMap::new());
pub static ALLOWED_REQUEST_UNLOCKS: RefCell<BTreeMap<(MultiLocation, MultiLocation), Assets>> = RefCell::new(BTreeMap::new());
pub static ALLOWED_UNLOCKS: RefCell<BTreeMap<(Location, Location), AssetsInHolding>> = RefCell::new(BTreeMap::new());
pub static ALLOWED_REQUEST_UNLOCKS: RefCell<BTreeMap<(Location, Location), AssetsInHolding>> = RefCell::new(BTreeMap::new());
}
pub fn take_lock_trace() -> Vec<LockTraceItem> {
LOCK_TRACE.with(|l| l.replace(Vec::new()))
}
pub fn allow_unlock(
unlocker: impl Into<MultiLocation>,
asset: impl Into<MultiAsset>,
owner: impl Into<MultiLocation>,
unlocker: impl Into<Location>,
asset: impl Into<Asset>,
owner: impl Into<Location>,
) {
ALLOWED_UNLOCKS.with(|l| {
l.borrow_mut()
@@ -557,9 +557,9 @@ pub fn allow_unlock(
});
}
pub fn disallow_unlock(
unlocker: impl Into<MultiLocation>,
asset: impl Into<MultiAsset>,
owner: impl Into<MultiLocation>,
unlocker: impl Into<Location>,
asset: impl Into<Asset>,
owner: impl Into<Location>,
) {
ALLOWED_UNLOCKS.with(|l| {
l.borrow_mut()
@@ -568,17 +568,17 @@ pub fn disallow_unlock(
.saturating_take(asset.into().into())
});
}
pub fn unlock_allowed(unlocker: &MultiLocation, asset: &MultiAsset, owner: &MultiLocation) -> bool {
pub fn unlock_allowed(unlocker: &Location, asset: &Asset, owner: &Location) -> bool {
ALLOWED_UNLOCKS.with(|l| {
l.borrow_mut()
.get(&(*owner, *unlocker))
.get(&(owner.clone(), unlocker.clone()))
.map_or(false, |x| x.contains_asset(asset))
})
}
pub fn allow_request_unlock(
locker: impl Into<MultiLocation>,
asset: impl Into<MultiAsset>,
owner: impl Into<MultiLocation>,
locker: impl Into<Location>,
asset: impl Into<Asset>,
owner: impl Into<Location>,
) {
ALLOWED_REQUEST_UNLOCKS.with(|l| {
l.borrow_mut()
@@ -588,9 +588,9 @@ pub fn allow_request_unlock(
});
}
pub fn disallow_request_unlock(
locker: impl Into<MultiLocation>,
asset: impl Into<MultiAsset>,
owner: impl Into<MultiLocation>,
locker: impl Into<Location>,
asset: impl Into<Asset>,
owner: impl Into<Location>,
) {
ALLOWED_REQUEST_UNLOCKS.with(|l| {
l.borrow_mut()
@@ -599,14 +599,10 @@ pub fn disallow_request_unlock(
.saturating_take(asset.into().into())
});
}
pub fn request_unlock_allowed(
locker: &MultiLocation,
asset: &MultiAsset,
owner: &MultiLocation,
) -> bool {
pub fn request_unlock_allowed(locker: &Location, asset: &Asset, owner: &Location) -> bool {
ALLOWED_REQUEST_UNLOCKS.with(|l| {
l.borrow_mut()
.get(&(*owner, *locker))
.get(&(owner.clone(), locker.clone()))
.map_or(false, |x| x.contains_asset(asset))
})
}
@@ -616,11 +612,11 @@ impl Enact for TestTicket {
fn enact(self) -> Result<(), LockError> {
match &self.0 {
LockTraceItem::Lock { unlocker, asset, owner } =>
allow_unlock(*unlocker, asset.clone(), *owner),
allow_unlock(unlocker.clone(), asset.clone(), owner.clone()),
LockTraceItem::Unlock { unlocker, asset, owner } =>
disallow_unlock(*unlocker, asset.clone(), *owner),
disallow_unlock(unlocker.clone(), asset.clone(), owner.clone()),
LockTraceItem::Reduce { locker, asset, owner } =>
disallow_request_unlock(*locker, asset.clone(), *owner),
disallow_request_unlock(locker.clone(), asset.clone(), owner.clone()),
_ => {},
}
LOCK_TRACE.with(move |l| l.borrow_mut().push(self.0));
@@ -635,38 +631,34 @@ impl AssetLock for TestAssetLock {
type ReduceTicket = TestTicket;
fn prepare_lock(
unlocker: MultiLocation,
asset: MultiAsset,
owner: MultiLocation,
unlocker: Location,
asset: Asset,
owner: Location,
) -> Result<Self::LockTicket, LockError> {
ensure!(assets(owner).contains_asset(&asset), LockError::AssetNotOwned);
ensure!(assets(owner.clone()).contains_asset(&asset), LockError::AssetNotOwned);
Ok(TestTicket(LockTraceItem::Lock { unlocker, asset, owner }))
}
fn prepare_unlock(
unlocker: MultiLocation,
asset: MultiAsset,
owner: MultiLocation,
unlocker: Location,
asset: Asset,
owner: Location,
) -> Result<Self::UnlockTicket, LockError> {
ensure!(unlock_allowed(&unlocker, &asset, &owner), LockError::NotLocked);
Ok(TestTicket(LockTraceItem::Unlock { unlocker, asset, owner }))
}
fn note_unlockable(
locker: MultiLocation,
asset: MultiAsset,
owner: MultiLocation,
) -> Result<(), LockError> {
allow_request_unlock(locker, asset.clone(), owner);
fn note_unlockable(locker: Location, asset: Asset, owner: Location) -> Result<(), LockError> {
allow_request_unlock(locker.clone(), asset.clone(), owner.clone());
let item = LockTraceItem::Note { locker, asset, owner };
LOCK_TRACE.with(move |l| l.borrow_mut().push(item));
Ok(())
}
fn prepare_reduce_unlockable(
locker: MultiLocation,
asset: MultiAsset,
owner: MultiLocation,
locker: Location,
asset: Asset,
owner: Location,
) -> Result<Self::ReduceTicket, xcm_executor::traits::LockError> {
ensure!(request_unlock_allowed(&locker, &asset, &owner), LockError::NotLocked);
Ok(TestTicket(LockTraceItem::Reduce { locker, asset, owner }))
@@ -674,26 +666,26 @@ impl AssetLock for TestAssetLock {
}
thread_local! {
pub static EXCHANGE_ASSETS: RefCell<Assets> = RefCell::new(Assets::new());
pub static EXCHANGE_ASSETS: RefCell<AssetsInHolding> = RefCell::new(AssetsInHolding::new());
}
pub fn set_exchange_assets(assets: impl Into<MultiAssets>) {
pub fn set_exchange_assets(assets: impl Into<Assets>) {
EXCHANGE_ASSETS.with(|a| a.replace(assets.into().into()));
}
pub fn exchange_assets() -> MultiAssets {
pub fn exchange_assets() -> Assets {
EXCHANGE_ASSETS.with(|a| a.borrow().clone().into())
}
pub struct TestAssetExchange;
impl AssetExchange for TestAssetExchange {
fn exchange_asset(
_origin: Option<&MultiLocation>,
give: Assets,
want: &MultiAssets,
_origin: Option<&Location>,
give: AssetsInHolding,
want: &Assets,
maximal: bool,
) -> Result<Assets, Assets> {
) -> Result<AssetsInHolding, AssetsInHolding> {
let mut have = EXCHANGE_ASSETS.with(|l| l.borrow().clone());
ensure!(have.contains_assets(want), give);
let get = if maximal {
std::mem::replace(&mut have, Assets::new())
std::mem::replace(&mut have, AssetsInHolding::new())
} else {
have.saturating_take(want.clone().into())
};
@@ -703,16 +695,25 @@ impl AssetExchange for TestAssetExchange {
}
}
match_types! {
pub type SiblingPrefix: impl Contains<MultiLocation> = {
MultiLocation { parents: 1, interior: X1(Parachain(_)) }
};
pub type ChildPrefix: impl Contains<MultiLocation> = {
MultiLocation { parents: 0, interior: X1(Parachain(_)) }
};
pub type ParentPrefix: impl Contains<MultiLocation> = {
MultiLocation { parents: 1, interior: Here }
};
pub struct SiblingPrefix;
impl Contains<Location> for SiblingPrefix {
fn contains(loc: &Location) -> bool {
matches!(loc.unpack(), (1, [Parachain(_)]))
}
}
pub struct ChildPrefix;
impl Contains<Location> for ChildPrefix {
fn contains(loc: &Location) -> bool {
matches!(loc.unpack(), (0, [Parachain(_)]))
}
}
pub struct ParentPrefix;
impl Contains<Location> for ParentPrefix {
fn contains(loc: &Location) -> bool {
matches!(loc.unpack(), (1, []))
}
}
pub struct TestConfig;
@@ -743,7 +744,7 @@ impl Config for TestConfig {
type Aliasers = AliasForeignAccountId32<SiblingPrefix>;
}
pub fn fungible_multi_asset(location: MultiLocation, amount: u128) -> MultiAsset {
pub fn fungible_multi_asset(location: Location, amount: u128) -> Asset {
(AssetId::from(location), Fungibility::Fungible(amount)).into()
}
+46 -30
View File
@@ -18,7 +18,7 @@ use super::*;
#[test]
fn universal_origin_should_work() {
AllowUnpaidFrom::set(vec![X1(Parachain(1)).into(), X1(Parachain(2)).into()]);
AllowUnpaidFrom::set(vec![[Parachain(1)].into(), [Parachain(2)].into()]);
clear_universal_aliases();
// Parachain 1 may represent Kusama to us
add_universal_alias(Parachain(1), Kusama);
@@ -29,48 +29,57 @@ fn universal_origin_should_work() {
UniversalOrigin(GlobalConsensus(Kusama)),
TransferAsset { assets: (Parent, 100u128).into(), beneficiary: Here.into() },
]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(2),
message,
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete { used: Weight::from_parts(10, 10), error: XcmError::InvalidLocation }
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(10, 10), XcmError::InvalidLocation));
let message = Xcm(vec![
UniversalOrigin(GlobalConsensus(Kusama)),
TransferAsset { assets: (Parent, 100u128).into(), beneficiary: Here.into() },
]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete { used: Weight::from_parts(20, 20), error: XcmError::NotWithdrawable }
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(20, 20), XcmError::NotWithdrawable));
add_asset((Ancestor(2), GlobalConsensus(Kusama)), (Parent, 100));
let message = Xcm(vec![
UniversalOrigin(GlobalConsensus(Kusama)),
TransferAsset { assets: (Parent, 100u128).into(), beneficiary: Here.into() },
]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(20, 20)));
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(20, 20) });
assert_eq!(asset_list((Ancestor(2), GlobalConsensus(Kusama))), vec![]);
}
#[test]
fn export_message_should_work() {
// Bridge chain (assumed to be Relay) lets Parachain #1 have message execution for free.
AllowUnpaidFrom::set(vec![X1(Parachain(1)).into()]);
AllowUnpaidFrom::set(vec![[Parachain(1)].into()]);
// Local parachain #1 issues a transfer asset on Polkadot Relay-chain, transfering 100 Planck to
// Polkadot parachain #2.
let expected_message = Xcm(vec![TransferAsset {
@@ -83,14 +92,15 @@ fn export_message_should_work() {
destination: Here,
xcm: expected_message.clone(),
}]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(10, 10)));
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(10, 10) });
let uni_src = (ByGenesis([0; 32]), Parachain(42), Parachain(1)).into();
assert_eq!(
exported_xcm(),
@@ -101,40 +111,46 @@ fn export_message_should_work() {
#[test]
fn unpaid_execution_should_work() {
// Bridge chain (assumed to be Relay) lets Parachain #1 have message execution for free.
AllowUnpaidFrom::set(vec![X1(Parachain(1)).into()]);
AllowUnpaidFrom::set(vec![[Parachain(1)].into()]);
// Bridge chain (assumed to be Relay) lets Parachain #2 have message execution for free if it
// asks.
AllowExplicitUnpaidFrom::set(vec![X1(Parachain(2)).into()]);
AllowExplicitUnpaidFrom::set(vec![[Parachain(2)].into()]);
// Asking for unpaid execution of up to 9 weight on the assumption it is origin of #2.
let message = Xcm(vec![UnpaidExecution {
weight_limit: Limited(Weight::from_parts(9, 9)),
check_origin: Some(Parachain(2).into()),
}]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message.clone(),
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(10, 10), XcmError::BadOrigin));
let r = XcmExecutor::<TestConfig>::execute_xcm(
assert_eq!(
r,
Outcome::Incomplete { used: Weight::from_parts(10, 10), error: XcmError::BadOrigin }
);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(2),
message.clone(),
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(r, Outcome::Error(XcmError::Barrier));
assert_eq!(r, Outcome::Error { error: XcmError::Barrier });
let message = Xcm(vec![UnpaidExecution {
weight_limit: Limited(Weight::from_parts(10, 10)),
check_origin: Some(Parachain(2).into()),
}]);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(2),
message.clone(),
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(10, 10)));
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(10, 10) });
}
+24 -30
View File
@@ -115,14 +115,14 @@ impl pallet_assets::Config for Test {
}
parameter_types! {
pub const RelayLocation: MultiLocation = Here.into_location();
pub const RelayLocation: Location = Here.into_location();
pub const AnyNetwork: Option<NetworkId> = None;
pub UniversalLocation: InteriorMultiLocation = (ByGenesis([0; 32]), Parachain(42)).into();
pub UniversalLocation: InteriorLocation = (ByGenesis([0; 32]), Parachain(42)).into();
pub UnitWeightCost: u64 = 1_000;
pub static AdvertisedXcmVersion: u32 = 3;
pub const BaseXcmWeight: Weight = Weight::from_parts(1_000, 1_000);
pub CurrencyPerSecondPerByte: (AssetId, u128, u128) = (Concrete(RelayLocation::get()), 1, 1);
pub TrustedAssets: (MultiAssetFilter, MultiLocation) = (All.into(), Here.into());
pub CurrencyPerSecondPerByte: (AssetId, u128, u128) = (AssetId(RelayLocation::get()), 1, 1);
pub TrustedAssets: (AssetFilter, Location) = (All.into(), Here.into());
pub const MaxInstructions: u32 = 100;
pub const MaxAssetsIntoHolding: u32 = 64;
pub CheckingAccount: AccountId = XcmPallet::check_account();
@@ -130,28 +130,25 @@ parameter_types! {
type AssetIdForAssets = u128;
pub struct FromMultiLocationToAsset<MultiLocation, AssetId>(
core::marker::PhantomData<(MultiLocation, AssetId)>,
);
impl MaybeEquivalence<MultiLocation, AssetIdForAssets>
for FromMultiLocationToAsset<MultiLocation, AssetIdForAssets>
pub struct FromLocationToAsset<Location, AssetId>(core::marker::PhantomData<(Location, AssetId)>);
impl MaybeEquivalence<Location, AssetIdForAssets>
for FromLocationToAsset<Location, AssetIdForAssets>
{
fn convert(value: &MultiLocation) -> Option<AssetIdForAssets> {
match value {
MultiLocation { parents: 0, interior: Here } => Some(0 as AssetIdForAssets),
MultiLocation { parents: 1, interior: Here } => Some(1 as AssetIdForAssets),
MultiLocation { parents: 0, interior: X2(PalletInstance(1), GeneralIndex(index)) }
if ![0, 1].contains(index) =>
fn convert(value: &Location) -> Option<AssetIdForAssets> {
match value.unpack() {
(0, []) => Some(0 as AssetIdForAssets),
(1, []) => Some(1 as AssetIdForAssets),
(0, [PalletInstance(1), GeneralIndex(index)]) if ![0, 1].contains(index) =>
Some(*index as AssetIdForAssets),
_ => None,
}
}
fn convert_back(value: &AssetIdForAssets) -> Option<MultiLocation> {
fn convert_back(value: &AssetIdForAssets) -> Option<Location> {
match value {
0u128 => Some(MultiLocation { parents: 1, interior: Here }),
0u128 => Some(Location { parents: 1, interior: Here }),
para_id @ 1..=1000 =>
Some(MultiLocation { parents: 1, interior: X1(Parachain(*para_id as u32)) }),
Some(Location { parents: 1, interior: [Parachain(*para_id as u32)].into() }),
_ => None,
}
}
@@ -163,7 +160,7 @@ pub type LocalAssetsTransactor = FungiblesAdapter<
ConvertedConcreteId<
AssetIdForAssets,
Balance,
FromMultiLocationToAsset<MultiLocation, AssetIdForAssets>,
FromLocationToAsset<Location, AssetIdForAssets>,
JustTry,
>,
SovereignAccountOf,
@@ -187,10 +184,10 @@ impl WeightTrader for DummyWeightTrader {
fn buy_weight(
&mut self,
_weight: Weight,
_payment: xcm_executor::Assets,
_payment: xcm_executor::AssetsInHolding,
_context: &XcmContext,
) -> Result<xcm_executor::Assets, XcmError> {
Ok(xcm_executor::Assets::default())
) -> Result<xcm_executor::AssetsInHolding, XcmError> {
Ok(xcm_executor::AssetsInHolding::default())
}
}
@@ -228,13 +225,10 @@ parameter_types! {
pub struct TreasuryToAccount;
impl ConvertLocation<AccountId> for TreasuryToAccount {
fn convert_location(location: &MultiLocation) -> Option<AccountId> {
match location {
MultiLocation {
parents: 1,
interior:
X2(Parachain(42), Plurality { id: BodyId::Treasury, part: BodyPart::Voice }),
} => Some(TreasuryAccountId::get()), // Hardcoded test treasury account id
fn convert_location(location: &Location) -> Option<AccountId> {
match location.unpack() {
(1, [Parachain(42), Plurality { id: BodyId::Treasury, part: BodyPart::Voice }]) =>
Some(TreasuryAccountId::get()), // Hardcoded test treasury account id
_ => None,
}
}
@@ -277,7 +271,7 @@ pub const INITIAL_BALANCE: Balance = 100 * UNITS;
pub const MINIMUM_BALANCE: Balance = 1 * UNITS;
pub fn sibling_chain_account_id(para_id: u32, account: [u8; 32]) -> AccountId {
let location: MultiLocation =
let location: Location =
(Parent, Parachain(para_id), Junction::AccountId32 { id: account, network: None }).into();
SovereignAccountOf::convert_location(&location).unwrap()
}
+20 -8
View File
@@ -22,9 +22,9 @@ use frame_support::{assert_ok, traits::tokens::Pay};
/// Type representing both a location and an asset that is held at that location.
/// The id of the held asset is relative to the location where it is being held.
#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq)]
#[derive(Encode, Decode, Clone, PartialEq, Eq)]
pub struct AssetKind {
destination: MultiLocation,
destination: Location,
asset_id: AssetId,
}
@@ -37,8 +37,8 @@ impl sp_runtime::traits::TryConvert<AssetKind, LocatableAssetId> for LocatableAs
parameter_types! {
pub SenderAccount: AccountId = AccountId::new([3u8; 32]);
pub InteriorAccount: InteriorMultiLocation = AccountId32 { id: SenderAccount::get().into(), network: None }.into();
pub InteriorBody: InteriorMultiLocation = Plurality { id: BodyId::Treasury, part: BodyPart::Voice }.into();
pub InteriorAccount: InteriorLocation = AccountId32 { id: SenderAccount::get().into(), network: None }.into();
pub InteriorBody: InteriorLocation = Plurality { id: BodyId::Treasury, part: BodyPart::Voice }.into();
pub Timeout: BlockNumber = 5; // 5 blocks
}
@@ -91,13 +91,19 @@ fn pay_over_xcm_works() {
vec![((Parent, Parachain(2)).into(), expected_message, expected_hash)]
);
let (_, message, hash) = sent_xcm()[0].clone();
let (_, message, mut hash) = sent_xcm()[0].clone();
let message =
Xcm::<<XcmConfig as xcm_executor::Config>::RuntimeCall>::from(message.clone());
// Execute message in parachain 2 with parachain 42's origin
let origin = (Parent, Parachain(42));
XcmExecutor::<XcmConfig>::execute_xcm(origin, message, hash, Weight::MAX);
XcmExecutor::<XcmConfig>::prepare_and_execute(
origin,
message,
&mut hash,
Weight::MAX,
Weight::zero(),
);
assert_eq!(mock::Assets::balance(0, &recipient), amount);
});
}
@@ -152,13 +158,19 @@ fn pay_over_xcm_governance_body() {
vec![((Parent, Parachain(2)).into(), expected_message, expected_hash)]
);
let (_, message, hash) = sent_xcm()[0].clone();
let (_, message, mut hash) = sent_xcm()[0].clone();
let message =
Xcm::<<XcmConfig as xcm_executor::Config>::RuntimeCall>::from(message.clone());
// Execute message in parachain 2 with parachain 42's origin
let origin = (Parent, Parachain(42));
XcmExecutor::<XcmConfig>::execute_xcm(origin, message, hash, Weight::MAX);
XcmExecutor::<XcmConfig>::prepare_and_execute(
origin,
message,
&mut hash,
Weight::MAX,
Weight::zero(),
);
assert_eq!(mock::Assets::balance(relay_asset_index, &recipient), amount);
});
}
@@ -25,9 +25,9 @@ use frame_support::{
use sp_runtime::{traits::ConvertToValue, DispatchResult};
parameter_types! {
pub Interior: InteriorMultiLocation = Plurality { id: BodyId::Treasury, part: BodyPart::Voice }.into();
pub Interior: InteriorLocation = Plurality { id: BodyId::Treasury, part: BodyPart::Voice }.into();
pub Timeout: BlockNumber = 5;
pub AssetHub: MultiLocation = (Parent, Parachain(1)).into();
pub AssetHub: Location = (Parent, Parachain(1)).into();
pub AssetIdGeneralIndex: u128 = 100;
pub AssetHubAssetId: AssetId = (PalletInstance(1), GeneralIndex(AssetIdGeneralIndex::get())).into();
pub LocatableAsset: LocatableAssetId = LocatableAssetId { asset_id: AssetHubAssetId::get(), location: AssetHub::get() };
@@ -140,7 +140,7 @@ fn salary_pay_over_xcm_works() {
assert_ok!(Salary::payout(RuntimeOrigin::signed(recipient.clone())));
// Get message from mock transport layer
let (_, message, hash) = sent_xcm()[0].clone();
let (_, message, mut hash) = sent_xcm()[0].clone();
// Change type from `Xcm<()>` to `Xcm<RuntimeCall>` to be able to execute later
let message =
Xcm::<<XcmConfig as xcm_executor::Config>::RuntimeCall>::from(message.clone());
@@ -164,7 +164,13 @@ fn salary_pay_over_xcm_works() {
assert_eq!(message, expected_message);
// Execute message as the asset hub
XcmExecutor::<XcmConfig>::execute_xcm((Parent, Parachain(42)), message, hash, Weight::MAX);
XcmExecutor::<XcmConfig>::prepare_and_execute(
(Parent, Parachain(42)),
message,
&mut hash,
Weight::MAX,
Weight::zero(),
);
// Recipient receives the payment
assert_eq!(
+29 -15
View File
@@ -18,7 +18,7 @@ use super::*;
#[test]
fn pallet_query_should_work() {
AllowUnpaidFrom::set(vec![X1(Parachain(1)).into()]);
AllowUnpaidFrom::set(vec![[Parachain(1)].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 message = Xcm(vec![QueryPallet {
@@ -29,14 +29,15 @@ fn pallet_query_should_work() {
max_weight: Weight::from_parts(50, 50),
},
}]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(10, 10)));
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(10, 10) });
let expected_msg = Xcm::<()>(vec![QueryResponse {
query_id: 1,
@@ -50,7 +51,7 @@ fn pallet_query_should_work() {
#[test]
fn pallet_query_with_results_should_work() {
AllowUnpaidFrom::set(vec![X1(Parachain(1)).into()]);
AllowUnpaidFrom::set(vec![[Parachain(1)].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 message = Xcm(vec![QueryPallet {
@@ -61,14 +62,15 @@ fn pallet_query_with_results_should_work() {
max_weight: Weight::from_parts(50, 50),
},
}]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parachain(1),
message,
hash,
&mut hash,
Weight::from_parts(50, 50),
Weight::zero(),
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(10, 10)));
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(10, 10) });
let expected_msg = Xcm::<()>(vec![QueryResponse {
query_id: 1,
@@ -106,15 +108,27 @@ fn prepaid_result_of_query_should_get_free_execution() {
max_weight: Weight::from_parts(10, 10),
querier: Some(Here.into()),
}]);
let hash = fake_message_hash(&message);
let mut hash = fake_message_hash(&message);
let weight_limit = Weight::from_parts(10, 10);
// First time the response gets through since we're expecting it...
let r = XcmExecutor::<TestConfig>::execute_xcm(Parent, message.clone(), hash, weight_limit);
assert_eq!(r, Outcome::Complete(Weight::from_parts(10, 10)));
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parent,
message.clone(),
&mut hash,
weight_limit,
Weight::zero(),
);
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(10, 10) });
assert_eq!(response(query_id).unwrap(), the_response);
// Second time it doesn't, since we're not.
let r = XcmExecutor::<TestConfig>::execute_xcm(Parent, message.clone(), hash, weight_limit);
assert_eq!(r, Outcome::Error(XcmError::Barrier));
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parent,
message.clone(),
&mut hash,
weight_limit,
Weight::zero(),
);
assert_eq!(r, Outcome::Error { error: XcmError::Barrier });
}
+111 -36
View File
@@ -25,10 +25,16 @@ fn transacting_should_work() {
require_weight_at_most: Weight::from_parts(50, 50),
call: TestCall::Any(Weight::from_parts(50, 50), None).encode().into(),
}]);
let hash = fake_message_hash(&message);
let mut hash = fake_message_hash(&message);
let weight_limit = Weight::from_parts(60, 60);
let r = XcmExecutor::<TestConfig>::execute_xcm(Parent, message, hash, weight_limit);
assert_eq!(r, Outcome::Complete(Weight::from_parts(60, 60)));
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parent,
message,
&mut hash,
weight_limit,
Weight::zero(),
);
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(60, 60) });
}
#[test]
@@ -40,10 +46,19 @@ fn transacting_should_respect_max_weight_requirement() {
require_weight_at_most: Weight::from_parts(40, 40),
call: TestCall::Any(Weight::from_parts(50, 50), None).encode().into(),
}]);
let hash = fake_message_hash(&message);
let mut hash = fake_message_hash(&message);
let weight_limit = Weight::from_parts(60, 60);
let r = XcmExecutor::<TestConfig>::execute_xcm(Parent, message, hash, weight_limit);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(50, 50), XcmError::MaxWeightInvalid));
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parent,
message,
&mut hash,
weight_limit,
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete { used: Weight::from_parts(50, 50), error: XcmError::MaxWeightInvalid }
);
}
#[test]
@@ -57,20 +72,26 @@ fn transacting_should_refund_weight() {
.encode()
.into(),
}]);
let hash = fake_message_hash(&message);
let mut hash = fake_message_hash(&message);
let weight_limit = Weight::from_parts(60, 60);
let r = XcmExecutor::<TestConfig>::execute_xcm(Parent, message, hash, weight_limit);
assert_eq!(r, Outcome::Complete(Weight::from_parts(40, 40)));
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parent,
message,
&mut hash,
weight_limit,
Weight::zero(),
);
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(40, 40) });
}
#[test]
fn paid_transacting_should_refund_payment_for_unused_weight() {
let one: MultiLocation = AccountIndex64 { index: 1, network: None }.into();
AllowPaidFrom::set(vec![one]);
let one: Location = AccountIndex64 { index: 1, network: None }.into();
AllowPaidFrom::set(vec![one.clone()]);
add_asset(AccountIndex64 { index: 1, network: None }, (Parent, 200u128));
WeightPrice::set((Parent.into(), 1_000_000_000_000, 1024 * 1024));
let origin = one;
let origin = one.clone();
let fees = (Parent, 200u128).into();
let message = Xcm::<TestCall>(vec![
WithdrawAsset((Parent, 200u128).into()), // enough for 200 units of weight.
@@ -86,10 +107,16 @@ fn paid_transacting_should_refund_payment_for_unused_weight() {
RefundSurplus,
DepositAsset { assets: AllCounted(1).into(), beneficiary: one },
]);
let hash = fake_message_hash(&message);
let mut hash = fake_message_hash(&message);
let weight_limit = Weight::from_parts(100, 100);
let r = XcmExecutor::<TestConfig>::execute_xcm(origin, message, hash, weight_limit);
assert_eq!(r, Outcome::Complete(Weight::from_parts(60, 60)));
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
origin,
message,
&mut hash,
weight_limit,
Weight::zero(),
);
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(60, 60) });
assert_eq!(
asset_list(AccountIndex64 { index: 1, network: None }),
vec![(Parent, 80u128).into()]
@@ -112,10 +139,16 @@ fn report_successful_transact_status_should_work() {
max_weight: Weight::from_parts(5000, 5000),
}),
]);
let hash = fake_message_hash(&message);
let mut hash = fake_message_hash(&message);
let weight_limit = Weight::from_parts(70, 70);
let r = XcmExecutor::<TestConfig>::execute_xcm(Parent, message, hash, weight_limit);
assert_eq!(r, Outcome::Complete(Weight::from_parts(70, 70)));
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parent,
message,
&mut hash,
weight_limit,
Weight::zero(),
);
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(70, 70) });
let expected_msg = Xcm(vec![QueryResponse {
response: Response::DispatchResult(MaybeErrorCode::Success),
query_id: 42,
@@ -142,10 +175,16 @@ fn report_failed_transact_status_should_work() {
max_weight: Weight::from_parts(5000, 5000),
}),
]);
let hash = fake_message_hash(&message);
let mut hash = fake_message_hash(&message);
let weight_limit = Weight::from_parts(70, 70);
let r = XcmExecutor::<TestConfig>::execute_xcm(Parent, message, hash, weight_limit);
assert_eq!(r, Outcome::Complete(Weight::from_parts(70, 70)));
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parent,
message,
&mut hash,
weight_limit,
Weight::zero(),
);
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(70, 70) });
let expected_msg = Xcm(vec![QueryResponse {
response: Response::DispatchResult(vec![2].into()),
query_id: 42,
@@ -168,10 +207,16 @@ fn expect_successful_transact_status_should_work() {
},
ExpectTransactStatus(MaybeErrorCode::Success),
]);
let hash = fake_message_hash(&message);
let mut hash = fake_message_hash(&message);
let weight_limit = Weight::from_parts(70, 70);
let r = XcmExecutor::<TestConfig>::execute_xcm(Parent, message, hash, weight_limit);
assert_eq!(r, Outcome::Complete(Weight::from_parts(70, 70)));
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parent,
message,
&mut hash,
weight_limit,
Weight::zero(),
);
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(70, 70) });
let message = Xcm::<TestCall>(vec![
Transact {
@@ -181,10 +226,19 @@ fn expect_successful_transact_status_should_work() {
},
ExpectTransactStatus(MaybeErrorCode::Success),
]);
let hash = fake_message_hash(&message);
let mut hash = fake_message_hash(&message);
let weight_limit = Weight::from_parts(70, 70);
let r = XcmExecutor::<TestConfig>::execute_xcm(Parent, message, hash, weight_limit);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(70, 70), XcmError::ExpectationFalse));
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parent,
message,
&mut hash,
weight_limit,
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete { used: Weight::from_parts(70, 70), error: XcmError::ExpectationFalse }
);
}
#[test]
@@ -199,10 +253,16 @@ fn expect_failed_transact_status_should_work() {
},
ExpectTransactStatus(vec![2].into()),
]);
let hash = fake_message_hash(&message);
let mut hash = fake_message_hash(&message);
let weight_limit = Weight::from_parts(70, 70);
let r = XcmExecutor::<TestConfig>::execute_xcm(Parent, message, hash, weight_limit);
assert_eq!(r, Outcome::Complete(Weight::from_parts(70, 70)));
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parent,
message,
&mut hash,
weight_limit,
Weight::zero(),
);
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(70, 70) });
let message = Xcm::<TestCall>(vec![
Transact {
@@ -212,10 +272,19 @@ fn expect_failed_transact_status_should_work() {
},
ExpectTransactStatus(vec![2].into()),
]);
let hash = fake_message_hash(&message);
let mut hash = fake_message_hash(&message);
let weight_limit = Weight::from_parts(70, 70);
let r = XcmExecutor::<TestConfig>::execute_xcm(Parent, message, hash, weight_limit);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(70, 70), XcmError::ExpectationFalse));
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parent,
message,
&mut hash,
weight_limit,
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete { used: Weight::from_parts(70, 70), error: XcmError::ExpectationFalse }
);
}
#[test]
@@ -235,10 +304,16 @@ fn clear_transact_status_should_work() {
max_weight: Weight::from_parts(5000, 5000),
}),
]);
let hash = fake_message_hash(&message);
let mut hash = fake_message_hash(&message);
let weight_limit = Weight::from_parts(80, 80);
let r = XcmExecutor::<TestConfig>::execute_xcm(Parent, message, hash, weight_limit);
assert_eq!(r, Outcome::Complete(Weight::from_parts(80, 80)));
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parent,
message,
&mut hash,
weight_limit,
Weight::zero(),
);
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(80, 80) });
let expected_msg = Xcm(vec![QueryResponse {
response: Response::DispatchResult(MaybeErrorCode::Success),
query_id: 42,
@@ -25,23 +25,41 @@ fn simple_version_subscriptions_should_work() {
SetAppendix(Xcm(vec![])),
SubscribeVersion { query_id: 42, max_response_weight: Weight::from_parts(5000, 5000) },
]);
let hash = fake_message_hash(&message);
let mut hash = fake_message_hash(&message);
let weight_limit = Weight::from_parts(20, 20);
let r = XcmExecutor::<TestConfig>::execute_xcm(origin, message, hash, weight_limit);
assert_eq!(r, Outcome::Error(XcmError::Barrier));
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
origin,
message,
&mut hash,
weight_limit,
Weight::zero(),
);
assert_eq!(r, Outcome::Error { error: XcmError::Barrier });
let origin = Parachain(1000);
let message = Xcm::<TestCall>(vec![SubscribeVersion {
query_id: 42,
max_response_weight: Weight::from_parts(5000, 5000),
}]);
let hash = fake_message_hash(&message);
let mut hash = fake_message_hash(&message);
let weight_limit = Weight::from_parts(10, 10);
let r = XcmExecutor::<TestConfig>::execute_xcm(origin, message.clone(), hash, weight_limit);
assert_eq!(r, Outcome::Error(XcmError::Barrier));
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
origin,
message.clone(),
&mut hash,
weight_limit,
Weight::zero(),
);
assert_eq!(r, Outcome::Error { error: XcmError::Barrier });
let r = XcmExecutor::<TestConfig>::execute_xcm(Parent, message, hash, weight_limit);
assert_eq!(r, Outcome::Complete(Weight::from_parts(10, 10)));
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parent,
message,
&mut hash,
weight_limit,
Weight::zero(),
);
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(10, 10) });
assert_eq!(
SubscriptionRequests::get(),
@@ -53,33 +71,36 @@ fn simple_version_subscriptions_should_work() {
fn version_subscription_instruction_should_work() {
let origin = Parachain(1000);
let message = Xcm::<TestCall>(vec![
DescendOrigin(X1(AccountIndex64 { index: 1, network: None })),
DescendOrigin([AccountIndex64 { index: 1, network: None }].into()),
SubscribeVersion { query_id: 42, max_response_weight: Weight::from_parts(5000, 5000) },
]);
let hash = fake_message_hash(&message);
let mut hash = fake_message_hash(&message);
let weight_limit = Weight::from_parts(20, 20);
let r = XcmExecutor::<TestConfig>::execute_xcm_in_credit(
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
origin,
message,
hash,
&mut hash,
weight_limit,
weight_limit,
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(20, 20), XcmError::BadOrigin));
assert_eq!(
r,
Outcome::Incomplete { used: Weight::from_parts(20, 20), error: XcmError::BadOrigin }
);
let message = Xcm::<TestCall>(vec![
SetAppendix(Xcm(vec![])),
SubscribeVersion { query_id: 42, max_response_weight: Weight::from_parts(5000, 5000) },
]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm_in_credit(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
origin,
message,
hash,
&mut hash,
weight_limit,
weight_limit,
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(20, 20)));
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(20, 20) });
assert_eq!(
SubscriptionRequests::get(),
@@ -93,20 +114,38 @@ fn simple_version_unsubscriptions_should_work() {
let origin = Parachain(1000);
let message = Xcm::<TestCall>(vec![SetAppendix(Xcm(vec![])), UnsubscribeVersion]);
let hash = fake_message_hash(&message);
let mut hash = fake_message_hash(&message);
let weight_limit = Weight::from_parts(20, 20);
let r = XcmExecutor::<TestConfig>::execute_xcm(origin, message, hash, weight_limit);
assert_eq!(r, Outcome::Error(XcmError::Barrier));
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
origin,
message,
&mut hash,
weight_limit,
Weight::zero(),
);
assert_eq!(r, Outcome::Error { error: XcmError::Barrier });
let origin = Parachain(1000);
let message = Xcm::<TestCall>(vec![UnsubscribeVersion]);
let hash = fake_message_hash(&message);
let mut hash = fake_message_hash(&message);
let weight_limit = Weight::from_parts(10, 10);
let r = XcmExecutor::<TestConfig>::execute_xcm(origin, message.clone(), hash, weight_limit);
assert_eq!(r, Outcome::Error(XcmError::Barrier));
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
origin,
message.clone(),
&mut hash,
weight_limit,
Weight::zero(),
);
assert_eq!(r, Outcome::Error { error: XcmError::Barrier });
let r = XcmExecutor::<TestConfig>::execute_xcm(Parent, message, hash, weight_limit);
assert_eq!(r, Outcome::Complete(Weight::from_parts(10, 10)));
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Parent,
message,
&mut hash,
weight_limit,
Weight::zero(),
);
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(10, 10) });
assert_eq!(SubscriptionRequests::get(), vec![(Parent.into(), None)]);
assert_eq!(sent_xcm(), vec![]);
@@ -118,31 +157,34 @@ fn version_unsubscription_instruction_should_work() {
// Not allowed to do it when origin has been changed.
let message = Xcm::<TestCall>(vec![
DescendOrigin(X1(AccountIndex64 { index: 1, network: None })),
DescendOrigin([AccountIndex64 { index: 1, network: None }].into()),
UnsubscribeVersion,
]);
let hash = fake_message_hash(&message);
let mut hash = fake_message_hash(&message);
let weight_limit = Weight::from_parts(20, 20);
let r = XcmExecutor::<TestConfig>::execute_xcm_in_credit(
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
origin,
message,
hash,
&mut hash,
weight_limit,
weight_limit,
);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(20, 20), XcmError::BadOrigin));
assert_eq!(
r,
Outcome::Incomplete { used: Weight::from_parts(20, 20), error: XcmError::BadOrigin }
);
// Fine to do it when origin is untouched.
let message = Xcm::<TestCall>(vec![SetAppendix(Xcm(vec![])), UnsubscribeVersion]);
let hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm_in_credit(
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
origin,
message,
hash,
&mut hash,
weight_limit,
weight_limit,
);
assert_eq!(r, Outcome::Complete(Weight::from_parts(20, 20)));
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(20, 20) });
assert_eq!(SubscriptionRequests::get(), vec![(Parachain(1000).into(), None)]);
assert_eq!(sent_xcm(), vec![]);
+52 -15
View File
@@ -74,45 +74,78 @@ fn errors_should_return_unused_weight() {
// First xfer results in an error on the last message only
TransferAsset {
assets: (Here, 1u128).into(),
beneficiary: X1(AccountIndex64 { index: 3, network: None }).into(),
beneficiary: [AccountIndex64 { index: 3, network: None }].into(),
},
// Second xfer results in error third message and after
TransferAsset {
assets: (Here, 2u128).into(),
beneficiary: X1(AccountIndex64 { index: 3, network: None }).into(),
beneficiary: [AccountIndex64 { index: 3, network: None }].into(),
},
// Third xfer results in error second message and after
TransferAsset {
assets: (Here, 4u128).into(),
beneficiary: X1(AccountIndex64 { index: 3, network: None }).into(),
beneficiary: [AccountIndex64 { index: 3, network: None }].into(),
},
]);
// Weight limit of 70 is needed.
let limit = <TestConfig as Config>::Weigher::weight(&mut message).unwrap();
assert_eq!(limit, Weight::from_parts(30, 30));
let hash = fake_message_hash(&message);
let mut hash = fake_message_hash(&message);
let r = XcmExecutor::<TestConfig>::execute_xcm(Here, message.clone(), hash, limit);
assert_eq!(r, Outcome::Complete(Weight::from_parts(30, 30)));
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Here,
message.clone(),
&mut hash,
limit,
Weight::zero(),
);
assert_eq!(r, Outcome::Complete { used: Weight::from_parts(30, 30) });
assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![(Here, 7u128).into()]);
assert_eq!(asset_list(Here), vec![(Here, 4u128).into()]);
assert_eq!(sent_xcm(), vec![]);
let r = XcmExecutor::<TestConfig>::execute_xcm(Here, message.clone(), hash, limit);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(30, 30), XcmError::NotWithdrawable));
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Here,
message.clone(),
&mut hash,
limit,
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete { used: Weight::from_parts(30, 30), error: XcmError::NotWithdrawable }
);
assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![(Here, 10u128).into()]);
assert_eq!(asset_list(Here), vec![(Here, 1u128).into()]);
assert_eq!(sent_xcm(), vec![]);
let r = XcmExecutor::<TestConfig>::execute_xcm(Here, message.clone(), hash, limit);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(20, 20), XcmError::NotWithdrawable));
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Here,
message.clone(),
&mut hash,
limit,
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete { used: Weight::from_parts(20, 20), error: XcmError::NotWithdrawable }
);
assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![(Here, 11u128).into()]);
assert_eq!(asset_list(Here), vec![]);
assert_eq!(sent_xcm(), vec![]);
let r = XcmExecutor::<TestConfig>::execute_xcm(Here, message, hash, limit);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(10, 10), XcmError::NotWithdrawable));
let r = XcmExecutor::<TestConfig>::prepare_and_execute(
Here,
message,
&mut hash,
limit,
Weight::zero(),
);
assert_eq!(
r,
Outcome::Incomplete { used: Weight::from_parts(10, 10), error: XcmError::NotWithdrawable }
);
assert_eq!(asset_list(AccountIndex64 { index: 3, network: None }), vec![(Here, 11u128).into()]);
assert_eq!(asset_list(Here), vec![]);
assert_eq!(sent_xcm(), vec![]);
@@ -148,8 +181,8 @@ fn weight_bounds_should_respect_instructions_limit() {
#[test]
fn weight_trader_tuple_should_work() {
let para_1: MultiLocation = Parachain(1).into();
let para_2: MultiLocation = Parachain(2).into();
let para_1: Location = Parachain(1).into();
let para_2: Location = Parachain(2).into();
parameter_types! {
pub static HereWeightPrice: (AssetId, u128, u128) =
@@ -186,7 +219,11 @@ fn weight_trader_tuple_should_work() {
let mut traders = Traders::new();
// trader one failed; trader two buys weight
assert_eq!(
traders.buy_weight(Weight::from_parts(5, 5), fungible_multi_asset(para_1, 10).into(), &ctx),
traders.buy_weight(
Weight::from_parts(5, 5),
fungible_multi_asset(para_1.clone(), 10).into(),
&ctx
),
Ok(vec![].into()),
);
// trader two refunds
@@ -28,18 +28,18 @@ use SendError::*;
/// chain, itself situated at `universal_local` within the consensus universe. If
/// `dest` is not a location in remote consensus, then an error is returned.
pub fn ensure_is_remote(
universal_local: impl Into<InteriorMultiLocation>,
dest: impl Into<MultiLocation>,
) -> Result<(NetworkId, InteriorMultiLocation), MultiLocation> {
universal_local: impl Into<InteriorLocation>,
dest: impl Into<Location>,
) -> Result<(NetworkId, InteriorLocation), Location> {
let dest = dest.into();
let universal_local = universal_local.into();
let local_net = match universal_local.global_consensus() {
Ok(x) => x,
Err(_) => return Err(dest),
};
let universal_destination: InteriorMultiLocation = universal_local
let universal_destination: InteriorLocation = universal_local
.into_location()
.appended_with(dest)
.appended_with(dest.clone())
.map_err(|x| x.1)?
.try_into()?;
let (remote_dest, remote_net) = match universal_destination.split_first() {
@@ -59,18 +59,18 @@ pub fn ensure_is_remote(
pub struct UnpaidLocalExporter<Exporter, UniversalLocation>(
PhantomData<(Exporter, UniversalLocation)>,
);
impl<Exporter: ExportXcm, UniversalLocation: Get<InteriorMultiLocation>> SendXcm
impl<Exporter: ExportXcm, UniversalLocation: Get<InteriorLocation>> SendXcm
for UnpaidLocalExporter<Exporter, UniversalLocation>
{
type Ticket = Exporter::Ticket;
fn validate(
dest: &mut Option<MultiLocation>,
dest: &mut Option<Location>,
xcm: &mut Option<Xcm<()>>,
) -> SendResult<Exporter::Ticket> {
let d = dest.take().ok_or(MissingArgument)?;
let universal_source = UniversalLocation::get();
let devolved = match ensure_is_remote(universal_source, d) {
let devolved = match ensure_is_remote(universal_source.clone(), d) {
Ok(x) => x,
Err(d) => {
*dest = Some(d);
@@ -96,18 +96,18 @@ pub trait ExporterFor {
/// the bridge chain as well as payment for the use of the `ExportMessage` instruction.
fn exporter_for(
network: &NetworkId,
remote_location: &InteriorMultiLocation,
remote_location: &InteriorLocation,
message: &Xcm<()>,
) -> Option<(MultiLocation, Option<MultiAsset>)>;
) -> Option<(Location, Option<Asset>)>;
}
#[impl_trait_for_tuples::impl_for_tuples(30)]
impl ExporterFor for Tuple {
fn exporter_for(
network: &NetworkId,
remote_location: &InteriorMultiLocation,
remote_location: &InteriorLocation,
message: &Xcm<()>,
) -> Option<(MultiLocation, Option<MultiAsset>)> {
) -> Option<(Location, Option<Asset>)> {
for_tuples!( #(
if let Some(r) = Tuple::exporter_for(network, remote_location, message) {
return Some(r);
@@ -125,21 +125,21 @@ pub struct NetworkExportTableItem {
/// If `Some`, the requested remote location must be equal to one of the items in the vector.
/// These are locations in the remote network.
/// If `None`, then the check is skipped.
pub remote_location_filter: Option<Vec<InteriorMultiLocation>>,
pub remote_location_filter: Option<Vec<InteriorLocation>>,
/// Locally-routable bridge with bridging capabilities to the `remote_network` and
/// `remote_location`. See [`ExporterFor`] for more details.
pub bridge: MultiLocation,
pub bridge: Location,
/// The local payment.
/// See [`ExporterFor`] for more details.
pub payment: Option<MultiAsset>,
pub payment: Option<Asset>,
}
impl NetworkExportTableItem {
pub fn new(
remote_network: NetworkId,
remote_location_filter: Option<Vec<InteriorMultiLocation>>,
bridge: MultiLocation,
payment: Option<MultiAsset>,
remote_location_filter: Option<Vec<InteriorLocation>>,
bridge: Location,
payment: Option<Asset>,
) -> Self {
Self { remote_network, remote_location_filter, bridge, payment }
}
@@ -152,9 +152,9 @@ pub struct NetworkExportTable<T>(sp_std::marker::PhantomData<T>);
impl<T: Get<Vec<NetworkExportTableItem>>> ExporterFor for NetworkExportTable<T> {
fn exporter_for(
network: &NetworkId,
remote_location: &InteriorMultiLocation,
remote_location: &InteriorLocation,
_: &Xcm<()>,
) -> Option<(MultiLocation, Option<MultiAsset>)> {
) -> Option<(Location, Option<Asset>)> {
T::get()
.into_iter()
.find(|item| {
@@ -194,16 +194,16 @@ pub fn forward_id_for(original_id: &XcmHash) -> XcmHash {
pub struct UnpaidRemoteExporter<Bridges, Router, UniversalLocation>(
PhantomData<(Bridges, Router, UniversalLocation)>,
);
impl<Bridges: ExporterFor, Router: SendXcm, UniversalLocation: Get<InteriorMultiLocation>> SendXcm
impl<Bridges: ExporterFor, Router: SendXcm, UniversalLocation: Get<InteriorLocation>> SendXcm
for UnpaidRemoteExporter<Bridges, Router, UniversalLocation>
{
type Ticket = Router::Ticket;
fn validate(
dest: &mut Option<MultiLocation>,
dest: &mut Option<Location>,
msg: &mut Option<Xcm<()>>,
) -> SendResult<Router::Ticket> {
let d = dest.ok_or(MissingArgument)?;
let d = dest.clone().ok_or(MissingArgument)?;
let devolved = ensure_is_remote(UniversalLocation::get(), d).map_err(|_| NotApplicable)?;
let (remote_network, remote_location) = devolved;
let xcm = msg.take().ok_or(MissingArgument)?;
@@ -261,17 +261,18 @@ impl<Bridges: ExporterFor, Router: SendXcm, UniversalLocation: Get<InteriorMulti
pub struct SovereignPaidRemoteExporter<Bridges, Router, UniversalLocation>(
PhantomData<(Bridges, Router, UniversalLocation)>,
);
impl<Bridges: ExporterFor, Router: SendXcm, UniversalLocation: Get<InteriorMultiLocation>> SendXcm
impl<Bridges: ExporterFor, Router: SendXcm, UniversalLocation: Get<InteriorLocation>> SendXcm
for SovereignPaidRemoteExporter<Bridges, Router, UniversalLocation>
{
type Ticket = Router::Ticket;
fn validate(
dest: &mut Option<MultiLocation>,
dest: &mut Option<Location>,
msg: &mut Option<Xcm<()>>,
) -> SendResult<Router::Ticket> {
let d = *dest.as_ref().ok_or(MissingArgument)?;
let devolved = ensure_is_remote(UniversalLocation::get(), d).map_err(|_| NotApplicable)?;
let d = dest.as_ref().ok_or(MissingArgument)?;
let devolved =
ensure_is_remote(UniversalLocation::get(), d.clone()).map_err(|_| NotApplicable)?;
let (remote_network, remote_location) = devolved;
let xcm = msg.take().ok_or(MissingArgument)?;
@@ -299,7 +300,7 @@ impl<Bridges: ExporterFor, Router: SendXcm, UniversalLocation: Get<InteriorMulti
let mut message = Xcm(if let Some(ref payment) = maybe_payment {
let fees = payment
.clone()
.reanchored(&bridge, UniversalLocation::get())
.reanchored(&bridge, &UniversalLocation::get())
.map_err(|_| Unroutable)?;
vec![
WithdrawAsset(fees.clone().into()),
@@ -366,7 +367,7 @@ pub struct BridgeMessage {
/// The message destination as a *Universal Location*. This means it begins with a
/// `GlobalConsensus` junction describing the network under which global consensus happens.
/// If this does not match our global consensus then it's a fatal error.
pub universal_dest: VersionedInteriorMultiLocation,
pub universal_dest: VersionedInteriorLocation,
pub message: VersionedXcm<()>,
}
@@ -386,8 +387,8 @@ pub struct BridgeBlobDispatcher<Router, OurPlace, OurPlaceBridgeInstance>(
);
impl<
Router: SendXcm,
OurPlace: Get<InteriorMultiLocation>,
OurPlaceBridgeInstance: Get<Option<InteriorMultiLocation>>,
OurPlace: Get<InteriorLocation>,
OurPlaceBridgeInstance: Get<Option<InteriorLocation>>,
> DispatchBlob for BridgeBlobDispatcher<Router, OurPlace, OurPlaceBridgeInstance>
{
fn dispatch_blob(blob: Vec<u8>) -> Result<(), DispatchBlobError> {
@@ -396,7 +397,7 @@ impl<
our_universal.global_consensus().map_err(|()| DispatchBlobError::Unbridgable)?;
let BridgeMessage { universal_dest, message } =
Decode::decode(&mut &blob[..]).map_err(|_| DispatchBlobError::InvalidEncoding)?;
let universal_dest: InteriorMultiLocation = universal_dest
let universal_dest: InteriorLocation = universal_dest
.try_into()
.map_err(|_| DispatchBlobError::UnsupportedLocationVersion)?;
// `universal_dest` is the desired destination within the universe: first we need to check
@@ -437,9 +438,9 @@ pub struct HaulBlobExporter<Bridge, BridgedNetwork, DestinationVersion, Price>(
/// ```
impl<
Bridge: HaulBlob,
BridgedNetwork: Get<MultiLocation>,
BridgedNetwork: Get<Location>,
DestinationVersion: GetVersion,
Price: Get<MultiAssets>,
Price: Get<Assets>,
> ExportXcm for HaulBlobExporter<Bridge, BridgedNetwork, DestinationVersion, Price>
{
type Ticket = (Vec<u8>, XcmHash);
@@ -447,12 +448,12 @@ impl<
fn validate(
network: NetworkId,
_channel: u32,
universal_source: &mut Option<InteriorMultiLocation>,
destination: &mut Option<InteriorMultiLocation>,
universal_source: &mut Option<InteriorLocation>,
destination: &mut Option<InteriorLocation>,
message: &mut Option<Xcm<()>>,
) -> Result<((Vec<u8>, XcmHash), MultiAssets), SendError> {
) -> Result<((Vec<u8>, XcmHash), Assets), SendError> {
let (bridged_network, bridged_network_location_parents) = {
let MultiLocation { parents, interior: mut junctions } = BridgedNetwork::get();
let Location { parents, interior: mut junctions } = BridgedNetwork::get();
match junctions.take_first() {
Some(GlobalConsensus(network)) => (network, parents),
_ => return Err(SendError::NotApplicable),
@@ -467,8 +468,8 @@ impl<
let (universal_dest, version) =
match dest.pushed_front_with(GlobalConsensus(bridged_network)) {
Ok(d) => {
let version = DestinationVersion::get_version_for(&MultiLocation::from(
AncestorThen(bridged_network_location_parents, d),
let version = DestinationVersion::get_version_for(&Location::from(
AncestorThen(bridged_network_location_parents, d.clone()),
))
.ok_or(SendError::DestinationUnsupported)?;
(d, version)
@@ -501,7 +502,7 @@ impl<
let message = VersionedXcm::from(message)
.into_version(version)
.map_err(|()| SendError::DestinationUnsupported)?;
let universal_dest = VersionedInteriorMultiLocation::from(universal_dest)
let universal_dest = VersionedInteriorLocation::from(universal_dest)
.into_version(version)
.map_err(|()| SendError::DestinationUnsupported)?;
@@ -548,10 +549,10 @@ mod tests {
type Ticket = ();
fn validate(
_destination: &mut Option<MultiLocation>,
_destination: &mut Option<Location>,
_message: &mut Option<Xcm<()>>,
) -> SendResult<Self::Ticket> {
Ok(((), MultiAssets::new()))
Ok(((), Assets::new()))
}
fn deliver(_ticket: Self::Ticket) -> Result<XcmHash, SendError> {
@@ -562,10 +563,10 @@ mod tests {
/// Generic test case asserting that dest and msg is not consumed by `validate` implementation
/// of `SendXcm` in case of expected result.
fn ensure_validate_does_not_consume_dest_or_msg<S: SendXcm>(
dest: MultiLocation,
dest: Location,
assert_result: impl Fn(SendResult<S::Ticket>),
) {
let mut dest_wrapper = Some(dest);
let mut dest_wrapper = Some(dest.clone());
let msg = Xcm::<()>::new();
let mut msg_wrapper = Some(msg.clone());
@@ -580,19 +581,19 @@ mod tests {
fn remote_exporters_does_not_consume_dest_or_msg_on_not_applicable() {
frame_support::parameter_types! {
pub Local: NetworkId = ByGenesis([0; 32]);
pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(Local::get()), Parachain(1234));
pub UniversalLocation: InteriorLocation = [GlobalConsensus(Local::get()), Parachain(1234)].into();
pub DifferentRemote: NetworkId = ByGenesis([22; 32]);
// no routers
pub BridgeTable: Vec<NetworkExportTableItem> = vec![];
}
// check with local destination (should be remote)
let local_dest = (Parent, Parachain(5678)).into();
assert!(ensure_is_remote(UniversalLocation::get(), local_dest).is_err());
let local_dest: Location = (Parent, Parachain(5678)).into();
assert!(ensure_is_remote(UniversalLocation::get(), local_dest.clone()).is_err());
ensure_validate_does_not_consume_dest_or_msg::<
UnpaidRemoteExporter<NetworkExportTable<BridgeTable>, OkSender, UniversalLocation>,
>(local_dest, |result| assert_eq!(Err(NotApplicable), result));
>(local_dest.clone(), |result| assert_eq!(Err(NotApplicable), result));
ensure_validate_does_not_consume_dest_or_msg::<
SovereignPaidRemoteExporter<
@@ -603,12 +604,12 @@ mod tests {
>(local_dest, |result| assert_eq!(Err(NotApplicable), result));
// check with not applicable destination
let remote_dest = (Parent, Parent, DifferentRemote::get()).into();
assert!(ensure_is_remote(UniversalLocation::get(), remote_dest).is_ok());
let remote_dest: Location = (Parent, Parent, DifferentRemote::get()).into();
assert!(ensure_is_remote(UniversalLocation::get(), remote_dest.clone()).is_ok());
ensure_validate_does_not_consume_dest_or_msg::<
UnpaidRemoteExporter<NetworkExportTable<BridgeTable>, OkSender, UniversalLocation>,
>(remote_dest, |result| assert_eq!(Err(NotApplicable), result));
>(remote_dest.clone(), |result| assert_eq!(Err(NotApplicable), result));
ensure_validate_does_not_consume_dest_or_msg::<
SovereignPaidRemoteExporter<
@@ -623,15 +624,15 @@ mod tests {
fn network_export_table_works() {
frame_support::parameter_types! {
pub NetworkA: NetworkId = ByGenesis([0; 32]);
pub Parachain1000InNetworkA: InteriorMultiLocation = X1(Parachain(1000));
pub Parachain2000InNetworkA: InteriorMultiLocation = X1(Parachain(2000));
pub Parachain1000InNetworkA: InteriorLocation = [Parachain(1000)].into();
pub Parachain2000InNetworkA: InteriorLocation = [Parachain(2000)].into();
pub NetworkB: NetworkId = ByGenesis([1; 32]);
pub BridgeToALocation: MultiLocation = MultiLocation::new(1, X1(Parachain(1234)));
pub BridgeToBLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(4321)));
pub BridgeToALocation: Location = Location::new(1, [Parachain(1234)]);
pub BridgeToBLocation: Location = Location::new(1, [Parachain(4321)]);
pub PaymentForNetworkAAndParachain2000: MultiAsset = (MultiLocation::parent(), 150).into();
pub PaymentForNetworkAAndParachain2000: Asset = (Location::parent(), 150).into();
pub BridgeTable: sp_std::vec::Vec<NetworkExportTableItem> = sp_std::vec![
// NetworkA allows `Parachain(1000)` as remote location WITHOUT payment.
@@ -658,19 +659,19 @@ mod tests {
];
}
let test_data = vec![
(NetworkA::get(), X1(Parachain(1000)), Some((BridgeToALocation::get(), None))),
(NetworkA::get(), X2(Parachain(1000), GeneralIndex(1)), None),
let test_data: Vec<(NetworkId, InteriorLocation, Option<(Location, Option<Asset>)>)> = vec![
(NetworkA::get(), [Parachain(1000)].into(), Some((BridgeToALocation::get(), None))),
(NetworkA::get(), [Parachain(1000), GeneralIndex(1)].into(), None),
(
NetworkA::get(),
X1(Parachain(2000)),
[Parachain(2000)].into(),
Some((BridgeToALocation::get(), Some(PaymentForNetworkAAndParachain2000::get()))),
),
(NetworkA::get(), X2(Parachain(2000), GeneralIndex(1)), None),
(NetworkA::get(), X1(Parachain(3000)), None),
(NetworkB::get(), X1(Parachain(1000)), Some((BridgeToBLocation::get(), None))),
(NetworkB::get(), X1(Parachain(2000)), Some((BridgeToBLocation::get(), None))),
(NetworkB::get(), X1(Parachain(3000)), Some((BridgeToBLocation::get(), None))),
(NetworkA::get(), [Parachain(2000), GeneralIndex(1)].into(), None),
(NetworkA::get(), [Parachain(3000)].into(), None),
(NetworkB::get(), [Parachain(1000)].into(), Some((BridgeToBLocation::get(), None))),
(NetworkB::get(), [Parachain(2000)].into(), Some((BridgeToBLocation::get(), None))),
(NetworkB::get(), [Parachain(3000)].into(), Some((BridgeToBLocation::get(), None))),
];
for (network, remote_location, expected_result) in test_data {
+19 -19
View File
@@ -25,10 +25,10 @@ use frame_support::{
use parity_scale_codec::Decode;
use sp_runtime::traits::{SaturatedConversion, Saturating, Zero};
use sp_std::{marker::PhantomData, result::Result};
use xcm::latest::{prelude::*, Weight};
use xcm::latest::{prelude::*, GetWeight, Weight};
use xcm_executor::{
traits::{WeightBounds, WeightTrader},
Assets,
AssetsInHolding,
};
pub struct FixedWeightBounds<T, C, M>(PhantomData<(T, C, M)>);
@@ -114,16 +114,16 @@ where
}
/// Function trait for handling some revenue. Similar to a negative imbalance (credit) handler, but
/// for a `MultiAsset`. Sensible implementations will deposit the asset in some known treasury or
/// for a `Asset`. Sensible implementations will deposit the asset in some known treasury or
/// block-author account.
pub trait TakeRevenue {
/// Do something with the given `revenue`, which is a single non-wildcard `MultiAsset`.
fn take_revenue(revenue: MultiAsset);
/// Do something with the given `revenue`, which is a single non-wildcard `Asset`.
fn take_revenue(revenue: Asset);
}
/// Null implementation just burns the revenue.
impl TakeRevenue for () {
fn take_revenue(_revenue: MultiAsset) {}
fn take_revenue(_revenue: Asset) {}
}
/// Simple fee calculator that requires payment in a single fungible at a fixed rate.
@@ -143,9 +143,9 @@ impl<T: Get<(AssetId, u128, u128)>, R: TakeRevenue> WeightTrader for FixedRateOf
fn buy_weight(
&mut self,
weight: Weight,
payment: Assets,
payment: AssetsInHolding,
context: &XcmContext,
) -> Result<Assets, XcmError> {
) -> Result<AssetsInHolding, XcmError> {
log::trace!(
target: "xcm::weight",
"FixedRateOfFungible::buy_weight weight: {:?}, payment: {:?}, context: {:?}",
@@ -165,7 +165,7 @@ impl<T: Get<(AssetId, u128, u128)>, R: TakeRevenue> WeightTrader for FixedRateOf
Ok(unused)
}
fn refund_weight(&mut self, weight: Weight, context: &XcmContext) -> Option<MultiAsset> {
fn refund_weight(&mut self, weight: Weight, context: &XcmContext) -> Option<Asset> {
log::trace!(target: "xcm::weight", "FixedRateOfFungible::refund_weight weight: {:?}, context: {:?}", weight, context);
let (id, units_per_second, units_per_mb) = T::get();
let weight = weight.min(self.0);
@@ -194,22 +194,22 @@ impl<T: Get<(AssetId, u128, u128)>, R: TakeRevenue> Drop for FixedRateOfFungible
/// places any weight bought into the right account.
pub struct UsingComponents<
WeightToFee: WeightToFeeT<Balance = Currency::Balance>,
AssetId: Get<MultiLocation>,
AssetIdValue: Get<Location>,
AccountId,
Currency: CurrencyT<AccountId>,
OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
>(
Weight,
Currency::Balance,
PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>,
PhantomData<(WeightToFee, AssetIdValue, AccountId, Currency, OnUnbalanced)>,
);
impl<
WeightToFee: WeightToFeeT<Balance = Currency::Balance>,
AssetId: Get<MultiLocation>,
AssetIdValue: Get<Location>,
AccountId,
Currency: CurrencyT<AccountId>,
OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
> WeightTrader for UsingComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
> WeightTrader for UsingComponents<WeightToFee, AssetIdValue, AccountId, Currency, OnUnbalanced>
{
fn new() -> Self {
Self(Weight::zero(), Zero::zero(), PhantomData)
@@ -218,20 +218,20 @@ impl<
fn buy_weight(
&mut self,
weight: Weight,
payment: Assets,
payment: AssetsInHolding,
context: &XcmContext,
) -> Result<Assets, XcmError> {
) -> Result<AssetsInHolding, XcmError> {
log::trace!(target: "xcm::weight", "UsingComponents::buy_weight weight: {:?}, payment: {:?}, context: {:?}", weight, payment, context);
let amount = WeightToFee::weight_to_fee(&weight);
let u128_amount: u128 = amount.try_into().map_err(|_| XcmError::Overflow)?;
let required = (Concrete(AssetId::get()), u128_amount).into();
let required = (AssetId(AssetIdValue::get()), u128_amount).into();
let unused = payment.checked_sub(required).map_err(|_| XcmError::TooExpensive)?;
self.0 = self.0.saturating_add(weight);
self.1 = self.1.saturating_add(amount);
Ok(unused)
}
fn refund_weight(&mut self, weight: Weight, context: &XcmContext) -> Option<MultiAsset> {
fn refund_weight(&mut self, weight: Weight, context: &XcmContext) -> Option<Asset> {
log::trace!(target: "xcm::weight", "UsingComponents::refund_weight weight: {:?}, context: {:?}", weight, context);
let weight = weight.min(self.0);
let amount = WeightToFee::weight_to_fee(&weight);
@@ -239,7 +239,7 @@ impl<
self.1 = self.1.saturating_sub(amount);
let amount: u128 = amount.saturated_into();
if amount > 0 {
Some((AssetId::get(), amount).into())
Some((AssetIdValue::get(), amount).into())
} else {
None
}
@@ -247,7 +247,7 @@ impl<
}
impl<
WeightToFee: WeightToFeeT<Balance = Currency::Balance>,
AssetId: Get<MultiLocation>,
AssetId: Get<Location>,
AccountId,
Currency: CurrencyT<AccountId>,
OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,