mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-21 08:35:40 +00:00
Reanchor should return canonical location (#4470)
* Reanchor should return canonical * Formatting * Formatting * Update xcm/src/v1/multilocation.rs * Formatting * Fixes * Don't discard unreanchorable assets * Formatting * Docs * Fixes * Fixes * tidy
This commit is contained in:
@@ -116,13 +116,22 @@ impl From<Vec<u8>> for AssetId {
|
||||
|
||||
impl AssetId {
|
||||
/// Prepend a `MultiLocation` to a concrete asset, giving it a new root location.
|
||||
pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
|
||||
pub fn prepend_with(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
|
||||
if let AssetId::Concrete(ref mut l) = self {
|
||||
l.prepend_with(prepend.clone()).map_err(|_| ())?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Mutate the asset to represent the same value from the perspective of a new `target`
|
||||
/// location. The local chain's location is provided in `ancestry`.
|
||||
pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> {
|
||||
if let AssetId::Concrete(ref mut l) = self {
|
||||
l.reanchor(target, ancestry)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding `MultiAsset` value.
|
||||
pub fn into_multiasset(self, fun: Fungibility) -> MultiAsset {
|
||||
MultiAsset { fun, id: self }
|
||||
@@ -203,13 +212,24 @@ impl MultiAsset {
|
||||
}
|
||||
|
||||
/// Prepend a `MultiLocation` to a concrete asset, giving it a new root location.
|
||||
pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
|
||||
self.id.reanchor(prepend)
|
||||
pub fn prepend_with(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
|
||||
self.id.prepend_with(prepend)
|
||||
}
|
||||
|
||||
/// Prepend a `MultiLocation` to a concrete asset, giving it a new root location.
|
||||
pub fn reanchored(mut self, prepend: &MultiLocation) -> Result<Self, ()> {
|
||||
self.reanchor(prepend)?;
|
||||
/// Mutate the location of the asset identifier if concrete, giving it the same location
|
||||
/// relative to a `target` context. The local context is provided as `ancestry`.
|
||||
pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> {
|
||||
self.id.reanchor(target, ancestry)
|
||||
}
|
||||
|
||||
/// Mutate the location of the asset identifier if concrete, giving it the same location
|
||||
/// relative to a `target` context. The local context is provided as `ancestry`.
|
||||
pub fn reanchored(
|
||||
mut self,
|
||||
target: &MultiLocation,
|
||||
ancestry: &MultiLocation,
|
||||
) -> Result<Self, ()> {
|
||||
self.id.reanchor(target, ancestry)?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
@@ -415,8 +435,13 @@ impl MultiAssets {
|
||||
}
|
||||
|
||||
/// Prepend a `MultiLocation` to any concrete asset items, giving it a new root location.
|
||||
pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
|
||||
self.0.iter_mut().try_for_each(|i| i.reanchor(prepend))
|
||||
pub fn prepend_with(&mut self, prefix: &MultiLocation) -> Result<(), ()> {
|
||||
self.0.iter_mut().try_for_each(|i| i.prepend_with(prefix))
|
||||
}
|
||||
|
||||
/// Prepend a `MultiLocation` to any concrete asset items, giving it a new root location.
|
||||
pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> {
|
||||
self.0.iter_mut().try_for_each(|i| i.reanchor(target, ancestry))
|
||||
}
|
||||
|
||||
/// Return a reference to an item at a specific index or `None` if it doesn't exist.
|
||||
@@ -485,10 +510,10 @@ impl WildMultiAsset {
|
||||
}
|
||||
|
||||
/// Prepend a `MultiLocation` to any concrete asset components, giving it a new root location.
|
||||
pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
|
||||
pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> {
|
||||
use WildMultiAsset::*;
|
||||
match self {
|
||||
AllOf { ref mut id, .. } => id.reanchor(prepend).map_err(|_| ()),
|
||||
AllOf { ref mut id, .. } => id.reanchor(target, ancestry).map_err(|_| ()),
|
||||
All => Ok(()),
|
||||
}
|
||||
}
|
||||
@@ -547,10 +572,10 @@ impl MultiAssetFilter {
|
||||
}
|
||||
|
||||
/// Prepend a `MultiLocation` to any concrete asset components, giving it a new root location.
|
||||
pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
|
||||
pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> {
|
||||
match self {
|
||||
MultiAssetFilter::Definite(ref mut assets) => assets.reanchor(prepend),
|
||||
MultiAssetFilter::Wild(ref mut wild) => wild.reanchor(prepend),
|
||||
MultiAssetFilter::Definite(ref mut assets) => assets.reanchor(target, ancestry),
|
||||
MultiAssetFilter::Wild(ref mut wild) => wild.reanchor(target, ancestry),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,6 +323,60 @@ impl MultiLocation {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Mutate `self` so that it represents the same location from the point of view of `target`.
|
||||
/// The context of `self` is provided as `ancestry`.
|
||||
///
|
||||
/// Does not modify `self` in case of overflow.
|
||||
pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> {
|
||||
// TODO: https://github.com/paritytech/polkadot/issues/4489 Optimize this.
|
||||
|
||||
// 1. Use our `ancestry` to figure out how the `target` would address us.
|
||||
let inverted_target = ancestry.inverted(target)?;
|
||||
|
||||
// 2. Prepend `inverted_target` to `self` to get self's location from the perspective of
|
||||
// `target`.
|
||||
self.prepend_with(inverted_target).map_err(|_| ())?;
|
||||
|
||||
// 3. Given that we know some of `target` ancestry, ensure that any parents in `self` are
|
||||
// strictly needed.
|
||||
self.simplify(target.interior());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Treating `self` as a context, determine how it would be referenced by a `target` location.
|
||||
pub fn inverted(&self, target: &MultiLocation) -> Result<MultiLocation, ()> {
|
||||
use Junction::OnlyChild;
|
||||
let mut ancestry = self.clone();
|
||||
let mut junctions = Junctions::Here;
|
||||
for _ in 0..target.parent_count() {
|
||||
junctions = junctions
|
||||
.pushed_front_with(ancestry.interior.take_last().unwrap_or(OnlyChild))
|
||||
.map_err(|_| ())?;
|
||||
}
|
||||
let parents = target.interior().len() as u8;
|
||||
Ok(MultiLocation::new(parents, junctions))
|
||||
}
|
||||
|
||||
/// Remove any unneeded parents/junctions in `self` based on the given context it will be
|
||||
/// interpreted in.
|
||||
pub fn simplify(&mut self, context: &Junctions) {
|
||||
if context.len() < self.parents as usize {
|
||||
// Not enough context
|
||||
return
|
||||
}
|
||||
while self.parents > 0 {
|
||||
let maybe = context.at(context.len() - (self.parents as usize));
|
||||
match (self.interior.first(), maybe) {
|
||||
(Some(i), Some(j)) if i == j => {
|
||||
self.interior.take_first();
|
||||
self.parents -= 1;
|
||||
},
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A unit struct which can be converted into a `MultiLocation` of `parents` value 1.
|
||||
@@ -773,9 +827,82 @@ impl TryFrom<MultiLocation> for Junctions {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{Ancestor, AncestorThen, Junctions::*, MultiLocation, Parent, ParentThen};
|
||||
use crate::opaque::v1::{Junction::*, NetworkId::Any};
|
||||
use crate::opaque::v1::{Junction::*, NetworkId::*};
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
|
||||
#[test]
|
||||
fn inverted_works() {
|
||||
let ancestry: MultiLocation = (Parachain(1000), PalletInstance(42)).into();
|
||||
let target = (Parent, PalletInstance(69)).into();
|
||||
let expected = (Parent, PalletInstance(42)).into();
|
||||
let inverted = ancestry.inverted(&target).unwrap();
|
||||
assert_eq!(inverted, expected);
|
||||
|
||||
let ancestry: MultiLocation = (Parachain(1000), PalletInstance(42), GeneralIndex(1)).into();
|
||||
let target = (Parent, Parent, PalletInstance(69), GeneralIndex(2)).into();
|
||||
let expected = (Parent, Parent, PalletInstance(42), GeneralIndex(1)).into();
|
||||
let inverted = ancestry.inverted(&target).unwrap();
|
||||
assert_eq!(inverted, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simplify_basic_works() {
|
||||
let mut location: MultiLocation =
|
||||
(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
|
||||
let context = X2(Parachain(1000), PalletInstance(42));
|
||||
let expected = GeneralIndex(69).into();
|
||||
location.simplify(&context);
|
||||
assert_eq!(location, expected);
|
||||
|
||||
let mut location: MultiLocation = (Parent, PalletInstance(42), GeneralIndex(69)).into();
|
||||
let context = X1(PalletInstance(42));
|
||||
let expected = GeneralIndex(69).into();
|
||||
location.simplify(&context);
|
||||
assert_eq!(location, expected);
|
||||
|
||||
let mut location: MultiLocation = (Parent, PalletInstance(42), GeneralIndex(69)).into();
|
||||
let context = X2(Parachain(1000), PalletInstance(42));
|
||||
let expected = GeneralIndex(69).into();
|
||||
location.simplify(&context);
|
||||
assert_eq!(location, expected);
|
||||
|
||||
let mut location: MultiLocation =
|
||||
(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
|
||||
let context = X3(OnlyChild, Parachain(1000), PalletInstance(42));
|
||||
let expected = GeneralIndex(69).into();
|
||||
location.simplify(&context);
|
||||
assert_eq!(location, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simplify_incompatible_location_fails() {
|
||||
let mut location: MultiLocation =
|
||||
(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
|
||||
let context = X3(Parachain(1000), PalletInstance(42), GeneralIndex(42));
|
||||
let expected =
|
||||
(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
|
||||
location.simplify(&context);
|
||||
assert_eq!(location, expected);
|
||||
|
||||
let mut location: MultiLocation =
|
||||
(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
|
||||
let context = X1(Parachain(1000));
|
||||
let expected =
|
||||
(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
|
||||
location.simplify(&context);
|
||||
assert_eq!(location, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reanchor_works() {
|
||||
let mut id: MultiLocation = (Parent, Parachain(1000), GeneralIndex(42)).into();
|
||||
let ancestry = Parachain(2000).into();
|
||||
let target = (Parent, Parachain(1000)).into();
|
||||
let expected = GeneralIndex(42).into();
|
||||
id.reanchor(&target, &ancestry).unwrap();
|
||||
assert_eq!(id, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_and_decode_works() {
|
||||
let m = MultiLocation {
|
||||
|
||||
Reference in New Issue
Block a user