Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

XCM docs and tests #2948

Merged
50 commits merged into from
Jun 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
03d1470
WIP
kianenigma Apr 28, 2021
96d021d
Merge branch 'master' of github.com:paritytech/polkadot into kiz-alex…
kianenigma Apr 28, 2021
59de11d
add tests and docs for DoubleEncoded
apopiak Apr 27, 2021
71c9b5b
reformat parent_count
apopiak Apr 27, 2021
bbec29d
add test for match_and_split
apopiak Apr 27, 2021
b96f898
fix append_with docs and add tests
apopiak Apr 28, 2021
1b3bcc5
move Parachain enum variant to tuple
apopiak Apr 28, 2021
5b59ee6
Fix stuff
kianenigma Apr 28, 2021
bda5c91
Merge branch 'kiz-alex-test-xcm' of github.com:paritytech/polkadot in…
kianenigma Apr 28, 2021
928c20d
add to append test
apopiak Apr 28, 2021
1c3b644
simplify match
kianenigma Apr 28, 2021
3490809
Merge branch 'kiz-alex-test-xcm' of github.com:paritytech/polkadot in…
kianenigma Apr 28, 2021
f74a298
formatting
apopiak Apr 28, 2021
c951986
format and extend doc comments (including examples)
apopiak Apr 28, 2021
253f6ee
Merge branch 'kiz-alex-test-xcm' of github.com:paritytech/polkadot in…
apopiak Apr 28, 2021
b128b22
fix typo
apopiak Apr 28, 2021
2700952
add some doc comments
apopiak Apr 28, 2021
e7bf1c2
Merge branch 'kiz-alex-test-xcm' of github.com:paritytech/polkadot in…
apopiak Apr 28, 2021
a0c2c99
add test for location inverter
apopiak Apr 28, 2021
169fdba
Add more tests/docs
kianenigma Apr 29, 2021
b5b3e70
Merge branch 'kiz-alex-test-xcm' of github.com:paritytech/polkadot in…
kianenigma Apr 29, 2021
058648b
Fix build
kianenigma Apr 29, 2021
d1918b6
matches fungibles
kianenigma Apr 29, 2021
df78d38
currency adapter.
kianenigma Apr 29, 2021
c5198c9
add more tests for location inverter
apopiak Apr 29, 2021
0118bc3
Merge branch 'kiz-alex-test-xcm' of github.com:paritytech/polkadot in…
apopiak Apr 29, 2021
4645f31
extract max length magic number into constant
apopiak Apr 29, 2021
7790e5d
adapters.
kianenigma Apr 29, 2021
20fe978
Merge branch 'kiz-alex-test-xcm' of github.com:paritytech/polkadot in…
kianenigma Apr 29, 2021
4590856
Master.into()
kianenigma Apr 29, 2021
b98a29c
Apply suggestions from code review
kianenigma Apr 29, 2021
1a3d428
Master.into()
kianenigma May 6, 2021
dd2e85c
Merge branch 'master' of github.com:paritytech/polkadot into kiz-alex…
kianenigma May 7, 2021
192c2f5
Final touches.
kianenigma May 7, 2021
692baf4
Merge branch 'master' of github.com:paritytech/polkadot into kiz-alex…
kianenigma May 9, 2021
ac47999
Repot and fixes
kianenigma May 9, 2021
09f9118
Remove last todo
kianenigma May 9, 2021
37921ed
Apply suggestions from code review
kianenigma May 10, 2021
d12b36f
Update xcm/xcm-builder/src/barriers.rs
kianenigma May 12, 2021
db134b8
Update xcm/xcm-builder/src/barriers.rs
kianenigma May 12, 2021
e5a1b67
Update xcm/xcm-builder/src/currency_adapter.rs
kianenigma May 12, 2021
f4bf121
Update xcm/xcm-builder/src/filter_asset_location.rs
kianenigma May 12, 2021
a7af09b
Update xcm/xcm-builder/src/matches_fungible.rs
kianenigma May 12, 2021
91ecc09
Update xcm/xcm-executor/src/traits/conversion.rs
kianenigma May 12, 2021
291ab3b
Update xcm/xcm-executor/src/traits/conversion.rs
kianenigma May 12, 2021
73cba92
Update xcm/xcm-executor/src/traits/transact_asset.rs
kianenigma May 12, 2021
c57e637
Update xcm/xcm-executor/src/traits/should_execute.rs
kianenigma May 12, 2021
55473a3
Master.into()
kianenigma May 12, 2021
8aa0aa0
Merge branch 'kiz-alex-test-xcm' of github.com:paritytech/polkadot in…
kianenigma May 12, 2021
a52ac13
Merge branch 'master' into kiz-alex-test-xcm
shawntabrizi Jun 3, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions parachain/src/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,9 @@ impl Id {
}
}

/// Determine if a parachain is a system parachain or not.
pub trait IsSystem {
/// Returns `true` if a parachain is a system parachain, `false` otherwise.
fn is_system(&self) -> bool;
}

Expand Down
44 changes: 42 additions & 2 deletions xcm/src/double_encoded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
use alloc::vec::Vec;
use parity_scale_codec::{Encode, Decode};

/// Wrapper around the encoded and decoded versions of a value.
/// Caches the decoded value once computed.
#[derive(Encode, Decode)]
#[codec(encode_bound())]
#[codec(decode_bound())]
Expand All @@ -29,11 +31,12 @@ pub struct DoubleEncoded<T> {
impl<T> Clone for DoubleEncoded<T> {
fn clone(&self) -> Self { Self { encoded: self.encoded.clone(), decoded: None } }
}
impl<T> Eq for DoubleEncoded<T> {
}

impl<T> PartialEq for DoubleEncoded<T> {
fn eq(&self, other: &Self) -> bool { self.encoded.eq(&other.encoded) }
}
impl<T> Eq for DoubleEncoded<T> {}

impl<T> core::fmt::Debug for DoubleEncoded<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { self.encoded.fmt(f) }
}
Expand All @@ -46,29 +49,66 @@ impl<T> From<Vec<u8>> for DoubleEncoded<T> {

impl<T> DoubleEncoded<T> {
pub fn into<S>(self) -> DoubleEncoded<S> { DoubleEncoded::from(self) }

pub fn from<S>(e: DoubleEncoded<S>) -> Self {
Self {
encoded: e.encoded,
decoded: None,
}
}

/// Provides an API similar to `AsRef` that provides access to the inner value.
/// `AsRef` implementation would expect an `&Option<T>` return type.
pub fn as_ref(&self) -> Option<&T> {
self.decoded.as_ref()
}
}

impl<T: Decode> DoubleEncoded<T> {
/// Decode the inner encoded value and store it.
/// Returns a reference to the value in case of success and `Err(())` in case the decoding fails.
pub fn ensure_decoded(&mut self) -> Result<&T, ()> {
if self.decoded.is_none() {
self.decoded = T::decode(&mut &self.encoded[..]).ok();
}
self.decoded.as_ref().ok_or(())
}

/// Move the decoded value out or (if not present) decode `encoded`.
pub fn take_decoded(&mut self) -> Result<T, ()> {
self.decoded.take().or_else(|| T::decode(&mut &self.encoded[..]).ok()).ok_or(())
}

/// Provides an API similar to `TryInto` that allows fallible conversion to the inner value type.
/// `TryInto` implementation would collide with std blanket implementation based on `TryFrom`.
pub fn try_into(mut self) -> Result<T, ()> {
self.ensure_decoded()?;
self.decoded.ok_or(())
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn ensure_decoded_works() {
let val: u64 = 42;
let mut encoded: DoubleEncoded<_> = Encode::encode(&val).into();
assert_eq!(encoded.ensure_decoded(), Ok(&val));
}

#[test]
fn take_decoded_works() {
let val: u64 = 42;
let mut encoded: DoubleEncoded<_> = Encode::encode(&val).into();
assert_eq!(encoded.take_decoded(), Ok(val));
}

#[test]
fn try_into_works() {
let val: u64 = 42;
let encoded: DoubleEncoded<_> = Encode::encode(&val).into();
assert_eq!(encoded.try_into(), Ok(val));
}
}
122 changes: 93 additions & 29 deletions xcm/src/v0/multi_asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,35 +61,34 @@ pub enum AssetInstance {
/// ### Abstract identifiers
///
/// Abstract identifiers are absolute identifiers that represent a notional asset which can exist within multiple
/// consensus systems. These tend to be simpler to deal with since their broad meaning is unchanged regardless stay
/// of the consensus system in which it is interpreted.
/// consensus systems. These tend to be simpler to deal with since their broad meaning is unchanged regardless stay of
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to prevent myself from doing so many of these and reverted most 🙈 but FYI this is only properly rewrapping the doc to 120 chars.

/// the consensus system in which it is interpreted.
///
/// However, in the attempt to provide uniformity across consensus systems, they may conflate different instantiations
/// of some notional asset (e.g. the reserve asset and a local reserve-backed derivative of it) under the same name,
/// leading to confusion. It also implies that one notional asset is accounted for locally in only one way. This may
/// not be the case, e.g. where there are multiple bridge instances each providing a bridged "BTC" token yet none
/// being fungible between the others.
/// leading to confusion. It also implies that one notional asset is accounted for locally in only one way. This may not
/// be the case, e.g. where there are multiple bridge instances each providing a bridged "BTC" token yet none being
/// fungible between the others.
///
/// Since they are meant to be absolute and universal, a global registry is needed to ensure that name collisions
/// do not occur.
/// Since they are meant to be absolute and universal, a global registry is needed to ensure that name collisions do not
/// occur.
///
/// An abstract identifier is represented as a simple variable-size byte string. As of writing, no global registry
/// exists and no proposals have been put forth for asset labeling.
///
/// ### Concrete identifiers
///
/// Concrete identifiers are *relative identifiers* that specifically identify a single asset through its location in
/// a consensus system relative to the context interpreting. Use of a `MultiLocation` ensures that similar but non
/// fungible variants of the same underlying asset can be properly distinguished, and obviates the need for any kind
/// of central registry.
/// Concrete identifiers are *relative identifiers* that specifically identify a single asset through its location in a
/// consensus system relative to the context interpreting. Use of a `MultiLocation` ensures that similar but non
/// fungible variants of the same underlying asset can be properly distinguished, and obviates the need for any kind of
/// central registry.
///
/// The limitation is that the asset identifier cannot be trivially copied between consensus
/// systems and must instead be "re-anchored" whenever being moved to a new consensus system, using the two systems'
/// relative paths.
/// The limitation is that the asset identifier cannot be trivially copied between consensus systems and must instead be
/// "re-anchored" whenever being moved to a new consensus system, using the two systems' relative paths.
///
/// Throughout XCM, messages are authored such that *when interpreted from the receiver's point of view* they will
/// have the desired meaning/effect. This means that relative paths should always by constructed to be read from the
/// point of view of the receiving system, *which may be have a completely different meaning in the authoring system*.
/// Throughout XCM, messages are authored such that *when interpreted from the receiver's point of view* they will have
/// the desired meaning/effect. This means that relative paths should always by constructed to be read from the point of
/// view of the receiving system, *which may be have a completely different meaning in the authoring system*.
///
/// Concrete identifiers are the preferred way of identifying an asset since they are entirely unambiguous.
///
Expand All @@ -99,8 +98,8 @@ pub enum AssetInstance {
///
/// - `<chain>/PalletInstance(<id>)` for a Frame chain with a single-asset pallet instance (such as an instance of the
/// Balances pallet).
/// - `<chain>/PalletInstance(<id>)/GeneralIndex(<index>)` for a Frame chain with an indexed multi-asset pallet
/// instance (such as an instance of the Assets pallet).
/// - `<chain>/PalletInstance(<id>)/GeneralIndex(<index>)` for a Frame chain with an indexed multi-asset pallet instance
/// (such as an instance of the Assets pallet).
/// - `<chain>/AccountId32` for an ERC-20-style single-asset smart-contract on a Frame-based contracts chain.
/// - `<chain>/AccountKey20` for an ERC-20-style single-asset smart-contract on an Ethereum-like chain.
///
Expand Down Expand Up @@ -147,6 +146,9 @@ pub enum MultiAsset {
}

impl MultiAsset {
/// Returns `true` if the `MultiAsset` is a wildcard and can refer to classes of assets, instead of just one.
///
/// Typically can also be inferred by the name starting with `All`.
pub fn is_wildcard(&self) -> bool {
match self {
MultiAsset::None
Expand Down Expand Up @@ -209,7 +211,6 @@ impl MultiAsset {
fn is_concrete_fungible(&self, id: &MultiLocation) -> bool {
match self {
MultiAsset::AllFungible => true,

MultiAsset::AllConcreteFungible { id: i }
| MultiAsset::ConcreteFungible { id: i, .. }
=> i == id,
Expand Down Expand Up @@ -250,8 +251,13 @@ impl MultiAsset {

fn is_all(&self) -> bool { matches!(self, MultiAsset::All) }

/// Returns true if `self` is a super-set of the given `inner`.
///
/// Typically, any wildcard is never contained in anything else, and a wildcard can contain any other non-wildcard.
/// For more details, see the implementation and tests.
pub fn contains(&self, inner: &MultiAsset) -> bool {
use MultiAsset::*;

// Inner cannot be wild
if inner.is_wildcard() { return false }
// Everything contains nothing.
Expand All @@ -273,15 +279,16 @@ impl MultiAsset {
AllConcreteNonFungible { class } => inner.is_concrete_non_fungible(class),
AllAbstractNonFungible { class } => inner.is_abstract_non_fungible(class),

ConcreteFungible { id, amount }
=> matches!(inner, ConcreteFungible { id: i , amount: a } if i == id && a >= amount),
AbstractFungible { id, amount }
=> matches!(inner, AbstractFungible { id: i , amount: a } if i == id && a >= amount),
ConcreteNonFungible { class, instance }
=> matches!(inner, ConcreteNonFungible { class: i , instance: a } if i == class && a == instance),
AbstractNonFungible { class, instance }
=> matches!(inner, AbstractNonFungible { class: i , instance: a } if i == class && a == instance),

ConcreteFungible { id, amount } => matches!(
inner,
ConcreteFungible { id: inner_id , amount: inner_amount } if inner_id == id && amount >= inner_amount
),
AbstractFungible { id, amount } => matches!(
inner,
AbstractFungible { id: inner_id , amount: inner_amount } if inner_id == id && amount >= inner_amount
),
ConcreteNonFungible { .. } => self == inner,
AbstractNonFungible { .. } => self == inner,
_ => false,
}
}
Expand Down Expand Up @@ -313,3 +320,60 @@ impl TryFrom<VersionedMultiAsset> for MultiAsset {
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn contains_works() {
use alloc::vec;
use MultiAsset::*;
// trivial case: all contains any non-wildcard.
assert!(All.contains(&None));
assert!(All.contains(&AbstractFungible { id: alloc::vec![99u8], amount: 1 }));

// trivial case: none contains nothing, except itself.
assert!(None.contains(&None));
assert!(!None.contains(&AllFungible));
assert!(!None.contains(&All));

// A bit more sneaky: Nothing can contain wildcard, even All ir the thing itself.
assert!(!All.contains(&All));
assert!(!All.contains(&AllFungible));
assert!(!AllFungible.contains(&AllFungible));
assert!(!AllNonFungible.contains(&AllNonFungible));

// For fungibles, containing is basically equality, or equal id with higher amount.
assert!(
!AbstractFungible { id: vec![99u8], amount: 99 }
.contains(&AbstractFungible { id: vec![1u8], amount: 99 })
);
assert!(
AbstractFungible { id: vec![99u8], amount: 99 }
.contains(&AbstractFungible { id: vec![99u8], amount: 99 })
);
assert!(
AbstractFungible { id: vec![99u8], amount: 99 }
.contains(&AbstractFungible { id: vec![99u8], amount: 9 })
);
assert!(
!AbstractFungible { id: vec![99u8], amount: 99 }
.contains(&AbstractFungible { id: vec![99u8], amount: 100 })
);

// For non-fungibles, containing is equality.
assert!(
!AbstractNonFungible {class: vec![99u8], instance: AssetInstance::Index { id: 9 } }
.contains(&AbstractNonFungible { class: vec![98u8], instance: AssetInstance::Index { id: 9 } })
);
assert!(
!AbstractNonFungible { class: vec![99u8], instance: AssetInstance::Index { id: 8 } }
.contains(&AbstractNonFungible { class: vec![99u8], instance: AssetInstance::Index { id: 9 } })
);
assert!(
AbstractNonFungible { class: vec![99u8], instance: AssetInstance::Index { id: 9 } }
.contains(&AbstractNonFungible { class: vec![99u8], instance: AssetInstance::Index { id: 9 } })
);
}
}
Loading