mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-19 13:25:44 +00:00
8428f678fe
# 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>
192 lines
6.1 KiB
Rust
192 lines
6.1 KiB
Rust
// Copyright (C) Parity Technologies (UK) Ltd.
|
|
// This file is part of Polkadot.
|
|
|
|
// Substrate is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
|
|
// Substrate is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
//! XCM matcher API, used primarily for writing barrier conditions.
|
|
|
|
use core::ops::ControlFlow;
|
|
use frame_support::traits::ProcessMessageError;
|
|
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.
|
|
pub trait CreateMatcher {
|
|
/// The concrete matcher type.
|
|
type Matcher;
|
|
|
|
/// Method that creates and returns the matcher type from `Self`.
|
|
fn matcher(self) -> Self::Matcher;
|
|
}
|
|
|
|
impl<'a, Call> CreateMatcher for &'a mut [Instruction<Call>] {
|
|
type Matcher = Matcher<'a, Call>;
|
|
|
|
fn matcher(self) -> Self::Matcher {
|
|
let total_inst = self.len();
|
|
|
|
Matcher { xcm: self, current_idx: 0, total_inst }
|
|
}
|
|
}
|
|
|
|
/// API that allows to pattern-match against anything that is contained within an XCM.
|
|
///
|
|
/// The intended usage of the matcher API is to enable the ability to chain successive methods of
|
|
/// this trait together, along with the ? operator for the purpose of facilitating the writing,
|
|
/// maintenance and auditability of XCM barriers.
|
|
///
|
|
/// Example:
|
|
/// ```rust
|
|
/// use frame_support::traits::ProcessMessageError;
|
|
/// use xcm::latest::Instruction;
|
|
/// use staging_xcm_builder::{CreateMatcher, MatchXcm};
|
|
///
|
|
/// let mut msg = [Instruction::<()>::ClearOrigin];
|
|
/// let res = msg
|
|
/// .matcher()
|
|
/// .assert_remaining_insts(1)?
|
|
/// .match_next_inst(|inst| match inst {
|
|
/// Instruction::<()>::ClearOrigin => Ok(()),
|
|
/// _ => Err(ProcessMessageError::BadFormat),
|
|
/// });
|
|
/// assert!(res.is_ok());
|
|
///
|
|
/// Ok::<(), ProcessMessageError>(())
|
|
/// ```
|
|
pub trait MatchXcm {
|
|
/// The concrete instruction type. Necessary to specify as it changes between XCM versions.
|
|
type Inst;
|
|
/// 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;
|
|
|
|
/// Returns success if the number of instructions that still have not been iterated over
|
|
/// equals `n`, otherwise returns an error.
|
|
fn assert_remaining_insts(self, n: usize) -> Result<Self, Self::Error>
|
|
where
|
|
Self: Sized;
|
|
|
|
/// Accepts a closure `f` that contains an argument signifying the next instruction to be
|
|
/// iterated over. The closure can then be used to check whether the instruction matches a
|
|
/// given condition, and can also be used to mutate the fields of an instruction.
|
|
///
|
|
/// The closure `f` returns success when the instruction passes the condition, otherwise it
|
|
/// returns an error, which will ultimately be returned by this function.
|
|
fn match_next_inst<F>(self, f: F) -> Result<Self, Self::Error>
|
|
where
|
|
Self: Sized,
|
|
F: FnMut(&mut Self::Inst) -> Result<(), Self::Error>;
|
|
|
|
/// Attempts to continuously iterate through the instructions while applying `f` to each of
|
|
/// them, until either the last instruction or `cond` returns false.
|
|
///
|
|
/// If `f` returns an error, then iteration halts and the function returns that error.
|
|
/// Otherwise, `f` returns a `ControlFlow` which signifies whether the iteration breaks or
|
|
/// continues.
|
|
fn match_next_inst_while<C, F>(self, cond: C, f: F) -> Result<Self, Self::Error>
|
|
where
|
|
Self: Sized,
|
|
C: Fn(&Self::Inst) -> bool,
|
|
F: FnMut(&mut Self::Inst) -> Result<ControlFlow<()>, Self::Error>;
|
|
|
|
/// Iterate instructions forward until `cond` returns false. When there are no more instructions
|
|
/// to be read, an error is returned.
|
|
fn skip_inst_while<C>(self, cond: C) -> Result<Self, Self::Error>
|
|
where
|
|
Self: Sized,
|
|
C: Fn(&Self::Inst) -> bool,
|
|
{
|
|
Self::match_next_inst_while(self, cond, |_| Ok(ControlFlow::Continue(())))
|
|
}
|
|
}
|
|
|
|
/// Struct created from calling `fn matcher()` on a mutable slice of `Instruction`s.
|
|
///
|
|
/// Implements `MatchXcm` to allow an iterator-like API to match against each `Instruction`
|
|
/// contained within the slice, which facilitates the building of XCM barriers.
|
|
pub struct Matcher<'a, Call> {
|
|
pub(crate) xcm: &'a mut [Instruction<Call>],
|
|
pub(crate) current_idx: usize,
|
|
pub(crate) total_inst: usize,
|
|
}
|
|
|
|
impl<'a, Call> MatchXcm for Matcher<'a, Call> {
|
|
type Error = ProcessMessageError;
|
|
type Inst = Instruction<Call>;
|
|
type Loc = Location;
|
|
|
|
fn assert_remaining_insts(self, n: usize) -> Result<Self, Self::Error>
|
|
where
|
|
Self: Sized,
|
|
{
|
|
if self.total_inst - self.current_idx != n {
|
|
return Err(ProcessMessageError::BadFormat)
|
|
}
|
|
|
|
Ok(self)
|
|
}
|
|
|
|
fn match_next_inst<F>(mut self, mut f: F) -> Result<Self, Self::Error>
|
|
where
|
|
Self: Sized,
|
|
F: FnMut(&mut Self::Inst) -> Result<(), Self::Error>,
|
|
{
|
|
if self.current_idx < self.total_inst {
|
|
f(&mut self.xcm[self.current_idx])?;
|
|
self.current_idx += 1;
|
|
Ok(self)
|
|
} else {
|
|
Err(ProcessMessageError::BadFormat)
|
|
}
|
|
}
|
|
|
|
fn match_next_inst_while<C, F>(mut self, cond: C, mut f: F) -> Result<Self, Self::Error>
|
|
where
|
|
Self: Sized,
|
|
C: Fn(&Self::Inst) -> bool,
|
|
F: FnMut(&mut Self::Inst) -> Result<ControlFlow<()>, Self::Error>,
|
|
{
|
|
if self.current_idx >= self.total_inst {
|
|
return Err(ProcessMessageError::BadFormat)
|
|
}
|
|
|
|
while self.current_idx < self.total_inst && cond(&self.xcm[self.current_idx]) {
|
|
if let ControlFlow::Break(()) = f(&mut self.xcm[self.current_idx])? {
|
|
break
|
|
}
|
|
self.current_idx += 1;
|
|
}
|
|
|
|
Ok(self)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use std::{vec, vec::Vec};
|
|
use xcm::latest::prelude::*;
|
|
|
|
#[test]
|
|
fn match_next_inst_while_works() {
|
|
let mut xcm: Vec<Instruction<()>> = vec![ClearOrigin];
|
|
|
|
let _ = xcm
|
|
.matcher()
|
|
.match_next_inst_while(|_| true, |_| Ok(ControlFlow::Continue(())))
|
|
.unwrap();
|
|
}
|
|
}
|