* cargo fmt

* Create benchmarks for XCM instructions introduced in v3 (#4564)

* Create benchmarks for BurnAsset and ExpectAsset

* Add benchmarks for ExpectOrigin and ExpectError

* Add benchmarks for QueryPallet and ExpectPallet

* Add benchmarks for ReportTransactStatus and ClearTransactStatus

* cargo fmt

* Use AllPalletsWithSystem in mocks

* Update XCM generic benchmarks for westend

* Remove default impls for some XCM weight functions

* Fix compilation error

* Add weight_args helper attribute

* Remove manually written XcmWeightInfo

* Parse trailing comma

* Revert "Add weight_args helper attribute"

This reverts commit 3b7c47a6182e1b9227036c38b406d494c3fcf6fd.

* Fixes

* Fixes

* XCM v3: Introduce querier field into `QueryReponse` (#4732)

* Introduce querier field into QueryReponse

* Convert &Option<MultiLocation> to Option<&MultiLocation>

&Option<T> is almost always never quite useful, most of the time it
still gets converted to an Option<&T> via `as_ref`, so we should simply
make functions that accept Option<&T> instead.

* Fix tests

* cargo fmt

* Fix benchmarks

* Appease spellchecker

* Fix test

* Fix tests

* Fix test

* Fix mock

* Fixes

* Fix tests

* Add test for response queriers

* Update xcm/pallet-xcm/src/lib.rs

* Test for non-existence of querier

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>

* Fixes

* Fixes

* Add `starts_with` function to `MultiLocation` and `Junctions` (#4835)

* add matches_prefix function to MultiLocation and Junctions

* rename matches_prefix to starts_with

* remove unnecessary main in doc comment

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>

* Make use of starts_with in match_and_split

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>

* XCM v3: Bridge infrastructure (#4681)

* XCM bridge infrastructure

* Missing bit of cherry-pick

* Revamped XCM proc macros; new NetworkIds

* Fixes

* Formatting

* ExportMessage instruction and config type

* Add MessageExporter definitions

* Formatting

* Missing files

* Fixes

* Initial bridging config API

* Allow for two-stage XCM execution

* Update xcm/src/v3/mod.rs

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>

* XCM crate building again

* Initial bridging primitive

* Docs

* Docs

* More work

* More work

* Merge branch 'gav-xcm-v3' into gav-xcm-v3-bridging

* Make build

* WithComputedOrigin and SovereignPaidRemoteExporter

* Remove TODOs

* Slim bridge API and tests.

* Fixes

* More work

* First bridge test passing

* Formatting

* Another test

* Next round of bridging tests

* Repot tests

* Cleanups

* Paid bridging

* Formatting

* Tests

* Spelling

* Formatting

* Fees and refactoring

* Fixes

* Formatting

* Refactor SendXcm to become two-phase

* Fix tests

* Refactoring of SendXcm and ExportXcm complete

* Formatting

* Rename CannotReachDestination -> NotApplicable

* Remove XCM v0

* Minor grumbles

* Formatting

* Formatting

* Fixes

* Fixes

* Cleanup XCM config

* Fee handling

* Fixes

* Formatting

* Fixes

* Bump

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>

* Bump Substrate

* XCM v3: `ExchangeAsset` and Remote-locking (#4945)

* Asset Exchange and Locks

* Make sure XCM typers impl MaxEncodedLen

* Basic implementation for locks

* Bump Substrate

* Missing files

* Use new API

* Introduce  instruction

* Big refactor

* Docs

* Remove deprecated struct

* Remove deprecated struct

* Repot XCM builder tests

* ExchangeAsset test

* Exchange tests

* Locking tests

* Locking tests

* Fixes and tests

* Fixes

* Formatting

* Spelling

* Add simulator test for remote locking

* Fix tests

* Bump

* XCM v3: Support for non-fungibles (#4950)

* NFT support and a test

* New files.

* Integration tests for sending NFTs

* Formatting

* Broken Cargo features

* Use 2021 edition

* Fixes

* Formatting

* Formatting

* Update xcm/xcm-builder/src/asset_conversion.rs

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>

* Update xcm/xcm-builder/src/nonfungibles_adapter.rs

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>

* Update xcm/xcm-executor/src/lib.rs

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>

* Fixes

* Fixes

* Fixes

* Formatting

* Fixes

Co-authored-by: Bastian Köcher <info@kchr.de>
Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>

* XCM v3: Context & ID hash (#4756)

* send_xcm returns message hash

* cargo fmt

* Create topic register and instructions

* Fix weights

* Use tabs

* Sketch out XcmContext

* Fix doc test

* Add the XCM context as a parameter to executor trait fns

* Fixes

* Add XcmContext parameter

* Revert adding context as an arg to SendXcm trait methods

* Revert adding context argument to ConvertOrigin trait methods

* cargo fmt

* Do not change the API of XcmExecutor::execute

* Fixes

* Fixes

* Fixes

* Fixes

* Remove convenience method

* Fixes

* Fixes

* cargo fmt

* Fixes

* Add benchmarks for XCM topic instructions

* cargo run --quiet --profile=production  --features=runtime-benchmarks -- benchmark --chain=westend-dev --steps=50 --repeat=20 --pallet=pallet_xcm_benchmarks::generic --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --header=./file_header.txt --template=./xcm/pallet-xcm-benchmarks/template.hbs --output=./runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs

* Remove context argument on FilterAssetLocation

* Fixes

* Remove unused import

* Fixes

* Fixes

* Fixes

* Accept XCM hash parameter in ExecuteXcm trait methods

* cargo fmt

* Properly enable sp-io/std

* Fixes

* default-features = false

* Fixes

* Fixes

* Fixes

* Make XcmContext optional in withdraw_asset

* Fixes

* Fixes

* Fixes

* Modify tests to check for the correct XCM hash

* Small refactor

* cargo fmt

* Check for expected hash in xcm-builder unit tests

* Add doc comment for the optionality of the XCM context in withdraw_asset

* Update xcm/src/v3/traits.rs

* Update xcm/src/v3/traits.rs

* Store XcmContext and avoid rebuilding

* Use ref for XcmContext

* Formatting

* Fix incorrect hash CC @KiChjang

* Refactor and make clear fake hashes

* Fixes

* Fixes

* Fixes

* Fix broken hashing

* Docs

* Fixes

* Fixes

* Fixes

* Formatting

* Fixes

* Fixes

* Fixes

* Remove unknowable hash

* Formatting

* Use message hash for greater identifiability

* Formatting

* Fixes

* Formatting

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>
Co-authored-by: Parity Bot <admin@parity.io>

* Fixes

* Fixes

* Fixes

* Fixes

* Formatting

* Fixes

* Formatting

* Fixes

* Fixes

* Formatting

* Formatting

* Remove horrible names

* Bump

* Remove InvertLocation trait (#5092)

* Remove InvertLocation trait

* Remove unneeded functions

* Formatting

* Fixes

* Remove XCMv1 (#5094)

* Remove XCMv1

* Remove XCMv1

* Formatting

* Fixes

* Fixes

* Formatting

* derive serialize/deserialize for xcm primitives (#5036)

* derive serialize/deserialize for xcm primitives

* derive serialize/deserialize for xcm primitives

* update v3

* update v2

Co-authored-by: Gav Wood <gavin@parity.io>

* Update lock

* Fixes

* Add benchmarks for the ExchangeAsset instruction

* `AliasOrigin` instruction stub (#5122)

* AliasOrigin instruction stub

* Fixes

* Fixes

* Update substrate

* Fixes

* Ensure same array length before using copy_from_slice

* Fixes

* Add benchmarks for the UniversalOrigin instruction

* Remove unused import

* Remove unused import

* Add benchmarks for SetFeesMode instruction

* Add benchmarks for asset (un)locking instructions

* Leave AliasOrigin unbenchmarked

* Fixes after merge

* cargo fmt

* Fixes

* Fixes

* Set TrustedReserves to None on both Kusama and Westend

* Remove extraneous reserve_asset_deposited benchmark

* Fix universal_origin benchmark

* cargo run --quiet --profile=production  --features=runtime-benchmarks -- benchmark pallet --chain=westend-dev --steps=50 --repeat=20 --pallet=pallet_xcm_benchmarks::generic --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --header=./file_header.txt --template=./xcm/pallet-xcm-benchmarks/template.hbs --output=./runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs

* Don't rely on skipped benchmark functions

* Fixes

* cargo run --quiet --profile=production  --features=runtime-benchmarks -- benchmark pallet --chain=kusama-dev --steps=50 --repeat=20 --pallet=pallet_xcm_benchmarks::generic --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --header=./file_header.txt --template=./xcm/pallet-xcm-benchmarks/template.hbs --output=./runtime/kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs

* Fix unused variables

* Fixes

* Spelling

* Fixes

* Fix codec index of VersionedXcm

* Allows to customize how calls are dispatched from XCM (#5657)

* CallDispatcher trait

* fmt

* unused import

* fix test-runtime

* remove JustDispatch type

* fix typo in test-runtime

* missing CallDispatcher

* more missing CallDispatcher

* Update comment `NoteAssetLocked` -> `NoteUnlockable`

* Fixes

* Fixes

* Adjust MultiAssets weights based on new wild card variants

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Some late fixes for XCMv3 (#5237)

* Maximise chances that trapped assets can be reclaimed

* Do origin check as part of ExportMessage for security

* Formatting

* Fixes

* Cleanup export XCM APIs

* Formatting

* Update xcm/src/v3/junctions.rs

* UnpaidExecution instruction and associated barrier.

* Tighten barriers (ClearOrigin/QueryResponse)

* Allow only 1 ClearOrigin instruction in AllowTopLevelPaidExecutionFrom

* Bi-directional teleport accounting

* Revert other fix

* Build fixes]

* Tests build

* Benchmark fixes

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>

* Update Substrate

* Re-export `pub` stuff from universal_exports.rs + removed unecessary clone (#6145)

* Re-export `pub` stuff from universal_exports.rs

* Removed unnecessary clone

* Use 2D weights in XCM v3 (#6134)

* Depend upon sp-core instead of sp-runtime

* Make sp-io a dev-dependency

* Use 2D weights in XCM v3

* cargo fmt

* Add XCM pallet migration to runtimes

* Use from_parts

* cargo fmt

* Fixes

* cargo fmt

* Remove XCMWeight import

* Fixes

* Fixes

* Fixes

* Fixes

* Use translate in migration

* Increase max upward message size in tests

* Fix doc test

* Remove most uses of from_ref_time

* cargo fmt

* Fixes

* Fixes

* Add extrinsic benchmarking to XCM pallet

* cargo fmt

* Fixes

* Use old syntax

* cargo fmt

* Fixes

* Remove hardcoded weights

* Add XCM pallet to benchmarks

* Use successful origin

* Fix weird type parameter compilation issue

* Fixes

* ".git/.scripts/bench-bot.sh" runtime westend-dev pallet_xcm

* ".git/.scripts/bench-bot.sh" runtime rococo-dev pallet_xcm

* ".git/.scripts/bench-bot.sh" runtime kusama-dev pallet_xcm

* ".git/.scripts/bench-bot.sh" runtime polkadot-dev pallet_xcm

* Use benchmarked XCM pallet weights

* Fixes

* Fixes

* Use override instead of skip

* Fixes

* Fixes

* Fixes

* Fixes

* ".git/.scripts/bench-bot.sh" runtime polkadot-dev pallet_xcm

* Fixes

* ".git/.scripts/bench-bot.sh" runtime polkadot-dev pallet_xcm

* ".git/.scripts/bench-bot.sh" runtime westend-dev pallet_xcm

Co-authored-by: command-bot <>

* Replace Weight::MAX with 100b weight units

* Add test to ensure all_gte in barriers is correct

* Update xcm/src/v3/junction.rs

Co-authored-by: asynchronous rob <rphmeier@gmail.com>

* Add more weight tests

* cargo fmt

* Create thread_local in XCM executor to limit recursion depth (#6304)

* Create thread_local in XCM executor to limit recursion depth

* Add unit test for recursion limit

* Fix statefulness in tests

* Remove panic

* Use defer and environmental macro

* Fix the implementation

* Use nicer interface

* Change ThisNetwork to AnyNetwork

* Move recursion check up to top level

* cargo fmt

* Update comment

Co-authored-by: Bastian Köcher <info@kchr.de>

* Add upper limit on the number of overweight messages in the queue (#6298)

* Add upper limit on the number of ovwerweight messages in the queue

* Add newline

* Introduce whitelist for Transact and limit UMP processing to 10 messages per block (#6280)

* Add SafeCallFilter to XcmConfig

* Limit UMP to receive 10 messages every block

* Place 10 message limit on processing instead of receiving

* Always increment the message_processed count whenever a message is processed

* Add as_derivative to the Transact whitelist

* cargo fmt

* Fixes

* Update xcm/xcm-builder/src/universal_exports.rs

Co-authored-by: Branislav Kontur <bkontur@gmail.com>

* Fixes

* Fixes

* Remove topic register and instead use the topic field in XcmContext

* Derive some common traits for DispatchBlobError

* Fixes

* cargo fmt

* Fixes

* Fixes

* Fix comments

* Fixes

* Introduce WithOriginFilter and apply it as the CallDispatcher for runtimes

* Fixes

* Appease clippy and fixes

* Fixes

* Fix more clippy issues

* Fixes

* ".git/.scripts/bench-bot.sh" runtime polkadot-dev pallet_xcm

* ".git/.scripts/bench-bot.sh" runtime westend-dev pallet_xcm

* ".git/.scripts/bench-bot.sh" runtime westend-dev pallet_xcm

* Add benchmark function for ExportMessage

* Fix comment

* Add upper limit to DownwardMessageQueues size

* Add max size check for queue in can_queue_downward_message

* Fixes

* Make Transact runtime call configurable

* Return Weight::MAX when there is no successful send XCM origin

* Update substrate

* Fixes

* Fixes

* Remove ExportMessage benchmark

* Remove assertion on Transact instruction benchmark

* Make reachable destination configurable in XCM pallet benchmarks

* Fixes

* Fixes

* Remove cfg attribute in fuzzer

* Fixes

* Remove cfg attribute for XCM pallet in test runtime

* Fixes

* Use ReachableDest where possible

* Fixes

* Add benchmark for UnpaidExecution

* Update substrate

* Ensure benchmark functions pass filters

* Add runtime-benchmarks feature to fuzzer

* Ensure FixedRateOfFungible accounts for proof size weights

* cargo fmt

* Whitelist remark_with_event when runtime-benchmarks feature is enabled

* Use remark_with_event for Transact benchmarks

* Fix Cargo.lock

* Allow up to 3 DescendOrigin instructions before UnpaidExecution

* cargo fmt

* Edit code comment

* Check check_origin for unpaid execution privilege

* Fixes

* Small nits for xcm-v3 (#6408)

* Add possibility to skip benchmark for export_message

* ".git/.scripts/bench-bot.sh" xcm westend-dev pallet_xcm_benchmarks::generic

* Revert

* ".git/.scripts/bench-bot.sh" xcm westend-dev pallet_xcm_benchmarks::generic

* Add HaulBlobError to `fn haul_blob`

* ".git/.scripts/bench-bot.sh" xcm westend-dev pallet_xcm_benchmarks::generic

Co-authored-by: command-bot <>

* Revert changes to UnpaidExecution

* Change AllowUnpaidExecutionFrom to be explicit

* Fix log text

* cargo fmt

* Add benchmarks for XCM pallet version migration (#6448)

* Add benchmarks for XCM pallet version migration

* cargo fmt

* Fixes

* Fixes

* Fixes

* ".git/.scripts/bench-bot.sh" runtime westend-dev pallet_xcm

* ".git/.scripts/bench-bot.sh" runtime kusama-dev pallet_xcm

* ".git/.scripts/bench-bot.sh" runtime rococo-dev pallet_xcm

* ".git/.scripts/bench-bot.sh" runtime polkadot-dev pallet_xcm

* Fix benchmarks

* Fix benchmarks

* ".git/.scripts/bench-bot.sh" runtime westend-dev pallet_xcm

* ".git/.scripts/bench-bot.sh" runtime kusama-dev pallet_xcm

* ".git/.scripts/bench-bot.sh" runtime rococo-dev pallet_xcm

* ".git/.scripts/bench-bot.sh" runtime polkadot-dev pallet_xcm

Co-authored-by: command-bot <>

* Merge remote-tracking branch 'origin/master' into gav-xcm-v3

* Fixes

* Fix comments (#6470)

* Specify Ethereum networks by their chain id (#6286)

Co-authored-by: Squirrel <gilescope@gmail.com>

* Use  for Kusama

* Use WithComputedOrigin for Polkadot, Rococo and Westend

* Update lock

* Fix warning

* Update xcm/pallet-xcm/src/tests.rs

Co-authored-by: Squirrel <gilescope@gmail.com>

* Update runtime/parachains/src/ump/migration.rs

Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Update xcm/pallet-xcm/src/migration.rs

Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fixes

* cargo fmt

* Typo

* Update xcm/src/v3/mod.rs

Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Docs

* Docs

* Docs

* Docs

* Docs

* Update xcm/src/v3/multiasset.rs

Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add tests for MultiAssets::from_sorted_and_deduplicated

* Fail gracefully when same instance NFTs are detected during push

* Update Substrate to fix benchmarks

* Apply suggestions from code review

* Update runtime/kusama/src/xcm_config.rs

* Rename arguments

* Attempt to fix benchmark

* ".git/.scripts/commands/bench/bench.sh" runtime polkadot-dev runtime_parachains::ump

* Use actual weights for UMP pallet in Polkadot

* ".git/.scripts/commands/bench/bench.sh" runtime kusama-dev runtime_parachains::ump

* ".git/.scripts/commands/bench/bench.sh" runtime westend-dev runtime_parachains::ump

* ".git/.scripts/commands/bench/bench.sh" runtime rococo-dev runtime_parachains::ump

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>
Co-authored-by: Alexander Popiak <alexander.popiak@parity.io>
Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
Co-authored-by: Bastian Köcher <info@kchr.de>
Co-authored-by: Parity Bot <admin@parity.io>
Co-authored-by: stanly-johnson <stanlyjohnson@outlook.com>
Co-authored-by: nanocryk <6422796+nanocryk@users.noreply.github.com>
Co-authored-by: Branislav Kontur <bkontur@gmail.com>
Co-authored-by: asynchronous rob <rphmeier@gmail.com>
Co-authored-by: command-bot <>
Co-authored-by: Vincent Geddes <vincent.geddes@hey.com>
Co-authored-by: Squirrel <gilescope@gmail.com>
Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
This commit is contained in:
Gavin Wood
2023-01-17 04:04:34 -03:00
committed by GitHub
parent 2952ad6f44
commit 1a1bfd2af9
155 changed files with 19234 additions and 8436 deletions
+122
View File
@@ -0,0 +1,122 @@
// Copyright 2020 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot 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.
// Polkadot 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/>.
//! Support data structures for `MultiLocation`, primarily the `Junction` datatype.
use super::{BodyId, BodyPart, Junctions, MultiLocation, NetworkId};
use crate::v3::Junction as NewJunction;
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_core::{bounded::WeakBoundedVec, ConstU32};
/// A single item in a path to describe the relative location of a consensus system.
///
/// Each item assumes a pre-existing location as its context and is defined in terms of it.
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub enum Junction {
/// An indexed parachain belonging to and operated by the context.
///
/// Generally used when the context is a Polkadot Relay-chain.
Parachain(#[codec(compact)] u32),
/// A 32-byte identifier for an account of a specific network that is respected as a sovereign endpoint within
/// the context.
///
/// Generally used when the context is a Substrate-based chain.
AccountId32 { network: NetworkId, id: [u8; 32] },
/// An 8-byte index for an account of a specific network that is respected as a sovereign endpoint within
/// the context.
///
/// May be used when the context is a Frame-based chain and includes e.g. an indices pallet.
AccountIndex64 {
network: NetworkId,
#[codec(compact)]
index: u64,
},
/// A 20-byte identifier for an account of a specific network that is respected as a sovereign endpoint within
/// the context.
///
/// May be used when the context is an Ethereum or Bitcoin chain or smart-contract.
AccountKey20 { network: NetworkId, key: [u8; 20] },
/// An instanced, indexed pallet that forms a constituent part of the context.
///
/// Generally used when the context is a Frame-based chain.
PalletInstance(u8),
/// A non-descript index within the context location.
///
/// Usage will vary widely owing to its generality.
///
/// NOTE: Try to avoid using this and instead use a more specific item.
GeneralIndex(#[codec(compact)] u128),
/// A nondescript datum acting as a key within the context location.
///
/// Usage will vary widely owing to its generality.
///
/// NOTE: Try to avoid using this and instead use a more specific item.
GeneralKey(WeakBoundedVec<u8, ConstU32<32>>),
/// The unambiguous child.
///
/// Not currently used except as a fallback when deriving ancestry.
OnlyChild,
/// A pluralistic body existing within consensus.
///
/// Typical to be used to represent a governance origin of a chain, but could in principle be used to represent
/// things such as multisigs also.
Plurality { id: BodyId, part: BodyPart },
}
impl TryFrom<NewJunction> for Junction {
type Error = ();
fn try_from(value: NewJunction) -> Result<Self, Self::Error> {
use NewJunction::*;
Ok(match value {
Parachain(id) => Self::Parachain(id),
AccountId32 { network, id } => Self::AccountId32 { network: network.try_into()?, id },
AccountIndex64 { network, index } =>
Self::AccountIndex64 { network: network.try_into()?, index },
AccountKey20 { network, key } =>
Self::AccountKey20 { network: network.try_into()?, key },
PalletInstance(index) => Self::PalletInstance(index),
GeneralIndex(id) => Self::GeneralIndex(id),
GeneralKey(key) => Self::GeneralKey(
key[..]
.to_vec()
.try_into()
.expect("array is of size 32 and so will never be out of bounds; qed"),
),
OnlyChild => Self::OnlyChild,
Plurality { id, part } => Self::Plurality { id: id.into(), part: part.into() },
_ => return Err(()),
})
}
}
impl Junction {
/// Convert `self` into a `MultiLocation` containing 0 parents.
///
/// Similar to `Into::into`, except that this method can be used in a const evaluation context.
pub const fn into(self) -> MultiLocation {
MultiLocation { parents: 0, interior: Junctions::X1(self) }
}
/// Convert `self` into a `MultiLocation` containing `n` parents.
///
/// Similar to `Self::into`, with the added ability to specify the number of parent junctions.
pub const fn into_exterior(self, n: u8) -> MultiLocation {
MultiLocation { parents: n, interior: Junctions::X1(self) }
}
}
+392 -208
View File
@@ -50,23 +50,198 @@
//! `DepositAsset` instructions. Failing that, dispatch calls to `teleport_assets` and
//! `reserve_transfer_assets` will fail with `UnweighableMessage`.
use super::v1::{Order as OldOrder, Response as OldResponse, Xcm as OldXcm};
use crate::{DoubleEncoded, GetWeight};
use super::{
v3::{
BodyId as NewBodyId, BodyPart as NewBodyPart, Instruction as NewInstruction,
NetworkId as NewNetworkId, Response as NewResponse, WeightLimit as NewWeightLimit,
Xcm as NewXcm,
},
DoubleEncoded, GetWeight,
};
use alloc::{vec, vec::Vec};
use core::{fmt::Debug, result};
use derivative::Derivative;
use parity_scale_codec::{self, Decode, Encode};
use parity_scale_codec::{self, Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_core::{bounded::WeakBoundedVec, ConstU32};
mod junction;
mod multiasset;
mod multilocation;
mod traits;
pub use traits::{Error, ExecuteXcm, Outcome, Result, SendError, SendResult, SendXcm};
// These parts of XCM v1 have been unchanged in XCM v2, and are re-imported here.
pub use super::v1::{
Ancestor, AncestorThen, AssetId, AssetInstance, BodyId, BodyPart, Fungibility,
InteriorMultiLocation, Junction, Junctions, MultiAsset, MultiAssetFilter, MultiAssets,
MultiLocation, NetworkId, OriginKind, Parent, ParentThen, WildFungibility, WildMultiAsset,
pub use junction::Junction;
pub use multiasset::{
AssetId, AssetInstance, Fungibility, MultiAsset, MultiAssetFilter, MultiAssets,
WildFungibility, WildMultiAsset,
};
pub use multilocation::{
Ancestor, AncestorThen, InteriorMultiLocation, Junctions, MultiLocation, Parent, ParentThen,
};
pub use traits::{Error, ExecuteXcm, Outcome, Result, SendError, SendResult, SendXcm};
/// Basically just the XCM (more general) version of `ParachainDispatchOrigin`.
#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)]
pub enum OriginKind {
/// Origin should just be the native dispatch origin representation for the sender in the
/// local runtime framework. For Cumulus/Frame chains this is the `Parachain` or `Relay` origin
/// if coming from a chain, though there may be others if the `MultiLocation` XCM origin has a
/// primary/native dispatch origin form.
Native,
/// Origin should just be the standard account-based origin with the sovereign account of
/// the sender. For Cumulus/Frame chains, this is the `Signed` origin.
SovereignAccount,
/// Origin should be the super-user. For Cumulus/Frame chains, this is the `Root` origin.
/// This will not usually be an available option.
Superuser,
/// Origin should be interpreted as an XCM native origin and the `MultiLocation` should be
/// encoded directly in the dispatch origin unchanged. For Cumulus/Frame chains, this will be
/// the `pallet_xcm::Origin::Xcm` type.
Xcm,
}
/// A global identifier of an account-bearing consensus system.
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub enum NetworkId {
/// Unidentified/any.
Any,
/// Some named network.
Named(WeakBoundedVec<u8, ConstU32<32>>),
/// The Polkadot Relay chain
Polkadot,
/// Kusama.
Kusama,
}
impl TryInto<NetworkId> for Option<NewNetworkId> {
type Error = ();
fn try_into(self) -> result::Result<NetworkId, ()> {
use NewNetworkId::*;
Ok(match self {
None => NetworkId::Any,
Some(Polkadot) => NetworkId::Polkadot,
Some(Kusama) => NetworkId::Kusama,
_ => return Err(()),
})
}
}
/// An identifier of a pluralistic body.
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub enum BodyId {
/// The only body in its context.
Unit,
/// A named body.
Named(WeakBoundedVec<u8, ConstU32<32>>),
/// An indexed body.
Index(#[codec(compact)] u32),
/// The unambiguous executive body (for Polkadot, this would be the Polkadot council).
Executive,
/// The unambiguous technical body (for Polkadot, this would be the Technical Committee).
Technical,
/// The unambiguous legislative body (for Polkadot, this could be considered the opinion of a majority of
/// lock-voters).
Legislative,
/// The unambiguous judicial body (this doesn't exist on Polkadot, but if it were to get a "grand oracle", it
/// may be considered as that).
Judicial,
/// The unambiguous defense body (for Polkadot, an opinion on the topic given via a public referendum
/// on the `staking_admin` track).
Defense,
/// The unambiguous administration body (for Polkadot, an opinion on the topic given via a public referendum
/// on the `general_admin` track).
Administration,
/// The unambiguous treasury body (for Polkadot, an opinion on the topic given via a public referendum
/// on the `treasurer` track).
Treasury,
}
impl From<NewBodyId> for BodyId {
fn from(n: NewBodyId) -> Self {
use NewBodyId::*;
match n {
Unit => Self::Unit,
Moniker(n) => Self::Named(
n[..]
.to_vec()
.try_into()
.expect("array size is 4 and so will never be out of bounds; qed"),
),
Index(n) => Self::Index(n),
Executive => Self::Executive,
Technical => Self::Technical,
Legislative => Self::Legislative,
Judicial => Self::Judicial,
Defense => Self::Defense,
Administration => Self::Administration,
Treasury => Self::Treasury,
}
}
}
/// A part of a pluralistic body.
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub enum BodyPart {
/// The body's declaration, under whatever means it decides.
Voice,
/// A given number of members of the body.
Members {
#[codec(compact)]
count: u32,
},
/// A given number of members of the body, out of some larger caucus.
Fraction {
#[codec(compact)]
nom: u32,
#[codec(compact)]
denom: u32,
},
/// No less than the given proportion of members of the body.
AtLeastProportion {
#[codec(compact)]
nom: u32,
#[codec(compact)]
denom: u32,
},
/// More than than the given proportion of members of the body.
MoreThanProportion {
#[codec(compact)]
nom: u32,
#[codec(compact)]
denom: u32,
},
}
impl BodyPart {
/// Returns `true` if the part represents a strict majority (> 50%) of the body in question.
pub fn is_majority(&self) -> bool {
match self {
BodyPart::Fraction { nom, denom } if *nom * 2 > *denom => true,
BodyPart::AtLeastProportion { nom, denom } if *nom * 2 > *denom => true,
BodyPart::MoreThanProportion { nom, denom } if *nom * 2 >= *denom => true,
_ => false,
}
}
}
impl From<NewBodyPart> for BodyPart {
fn from(n: NewBodyPart) -> Self {
use NewBodyPart::*;
match n {
Voice => Self::Voice,
Members { count } => Self::Members { count },
Fraction { nom, denom } => Self::Fraction { nom, denom },
AtLeastProportion { nom, denom } => Self::AtLeastProportion { nom, denom },
MoreThanProportion { nom, denom } => Self::MoreThanProportion { nom, denom },
}
}
}
/// This module's XCM version.
pub const VERSION: super::Version = 2;
@@ -218,6 +393,17 @@ impl From<WeightLimit> for Option<u64> {
}
}
impl TryFrom<NewWeightLimit> for WeightLimit {
type Error = ();
fn try_from(x: NewWeightLimit) -> result::Result<Self, Self::Error> {
use NewWeightLimit::*;
match x {
Limited(w) => Ok(Self::Limited(w.ref_time())),
Unlimited => Ok(Self::Unlimited),
}
}
}
/// Local weight type; execution time in picoseconds.
pub type Weight = u64;
@@ -422,6 +608,12 @@ pub enum Instruction<RuntimeCall> {
/// A `QueryResponse` message of type `ExecutionOutcome` is sent to `dest` with the given
/// `query_id` and the outcome of the XCM.
///
/// - `query_id`: An identifier that will be replicated into the returned XCM message.
/// - `dest`: A valid destination for the returned XCM message.
/// - `max_response_weight`: The maximum amount of weight that the `QueryResponse` item which
/// is sent as a reply may take to execute. NOTE: If this is unexpectedly large then the
/// response may not execute at all.
///
/// Kind: *Instruction*
///
/// Errors:
@@ -633,7 +825,14 @@ pub enum Instruction<RuntimeCall> {
/// support in a `QueryResponse` instruction. Any changes to this should also elicit similar
/// responses when they happen.
///
/// - `query_id`: An identifier that will be replicated into the returned XCM message.
/// - `max_response_weight`: The maximum amount of weight that the `QueryResponse` item which
/// is sent as a reply may take to execute. NOTE: If this is unexpectedly large then the
/// response may not execute at all.
///
/// Kind: *Instruction*
///
/// Errors: *Fallible*
SubscribeVersion {
#[codec(compact)]
query_id: QueryId,
@@ -644,6 +843,8 @@ pub enum Instruction<RuntimeCall> {
/// Cancel the effect of a previous `SubscribeVersion` instruction.
///
/// Kind: *Instruction*
///
/// Errors: *Fallible*
UnsubscribeVersion,
}
@@ -708,48 +909,81 @@ impl<RuntimeCall> Instruction<RuntimeCall> {
// TODO: Automate Generation
impl<RuntimeCall, W: XcmWeightInfo<RuntimeCall>> GetWeight<W> for Instruction<RuntimeCall> {
fn weight(&self) -> Weight {
fn weight(&self) -> sp_weights::Weight {
use Instruction::*;
match self {
WithdrawAsset(assets) => W::withdraw_asset(assets),
ReserveAssetDeposited(assets) => W::reserve_asset_deposited(assets),
ReceiveTeleportedAsset(assets) => W::receive_teleported_asset(assets),
WithdrawAsset(assets) => sp_weights::Weight::from_ref_time(W::withdraw_asset(assets)),
ReserveAssetDeposited(assets) =>
sp_weights::Weight::from_ref_time(W::reserve_asset_deposited(assets)),
ReceiveTeleportedAsset(assets) =>
sp_weights::Weight::from_ref_time(W::receive_teleported_asset(assets)),
QueryResponse { query_id, response, max_weight } =>
W::query_response(query_id, response, max_weight),
TransferAsset { assets, beneficiary } => W::transfer_asset(assets, beneficiary),
sp_weights::Weight::from_ref_time(W::query_response(query_id, response, max_weight)),
TransferAsset { assets, beneficiary } =>
sp_weights::Weight::from_ref_time(W::transfer_asset(assets, beneficiary)),
TransferReserveAsset { assets, dest, xcm } =>
W::transfer_reserve_asset(&assets, dest, xcm),
sp_weights::Weight::from_ref_time(W::transfer_reserve_asset(&assets, dest, xcm)),
Transact { origin_type, require_weight_at_most, call } =>
W::transact(origin_type, require_weight_at_most, call),
sp_weights::Weight::from_ref_time(W::transact(
origin_type,
require_weight_at_most,
call,
)),
HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
W::hrmp_new_channel_open_request(sender, max_message_size, max_capacity),
HrmpChannelAccepted { recipient } => W::hrmp_channel_accepted(recipient),
sp_weights::Weight::from_ref_time(W::hrmp_new_channel_open_request(
sender,
max_message_size,
max_capacity,
)),
HrmpChannelAccepted { recipient } =>
sp_weights::Weight::from_ref_time(W::hrmp_channel_accepted(recipient)),
HrmpChannelClosing { initiator, sender, recipient } =>
W::hrmp_channel_closing(initiator, sender, recipient),
ClearOrigin => W::clear_origin(),
DescendOrigin(who) => W::descend_origin(who),
sp_weights::Weight::from_ref_time(W::hrmp_channel_closing(
initiator, sender, recipient,
)),
ClearOrigin => sp_weights::Weight::from_ref_time(W::clear_origin()),
DescendOrigin(who) => sp_weights::Weight::from_ref_time(W::descend_origin(who)),
ReportError { query_id, dest, max_response_weight } =>
W::report_error(query_id, dest, max_response_weight),
sp_weights::Weight::from_ref_time(W::report_error(
query_id,
dest,
max_response_weight,
)),
DepositAsset { assets, max_assets, beneficiary } =>
W::deposit_asset(assets, max_assets, beneficiary),
sp_weights::Weight::from_ref_time(W::deposit_asset(assets, max_assets, beneficiary)),
DepositReserveAsset { assets, max_assets, dest, xcm } =>
W::deposit_reserve_asset(assets, max_assets, dest, xcm),
ExchangeAsset { give, receive } => W::exchange_asset(give, receive),
InitiateReserveWithdraw { assets, reserve, xcm } =>
sp_weights::Weight::from_ref_time(W::deposit_reserve_asset(
assets, max_assets, dest, xcm,
)),
ExchangeAsset { give, receive } =>
sp_weights::Weight::from_ref_time(W::exchange_asset(give, receive)),
InitiateReserveWithdraw { assets, reserve, xcm } => sp_weights::Weight::from_ref_time(
W::initiate_reserve_withdraw(assets, reserve, xcm),
InitiateTeleport { assets, dest, xcm } => W::initiate_teleport(assets, dest, xcm),
),
InitiateTeleport { assets, dest, xcm } =>
sp_weights::Weight::from_ref_time(W::initiate_teleport(assets, dest, xcm)),
QueryHolding { query_id, dest, assets, max_response_weight } =>
W::query_holding(query_id, dest, assets, max_response_weight),
BuyExecution { fees, weight_limit } => W::buy_execution(fees, weight_limit),
RefundSurplus => W::refund_surplus(),
SetErrorHandler(xcm) => W::set_error_handler(xcm),
SetAppendix(xcm) => W::set_appendix(xcm),
ClearError => W::clear_error(),
ClaimAsset { assets, ticket } => W::claim_asset(assets, ticket),
Trap(code) => W::trap(code),
sp_weights::Weight::from_ref_time(W::query_holding(
query_id,
dest,
assets,
max_response_weight,
)),
BuyExecution { fees, weight_limit } =>
sp_weights::Weight::from_ref_time(W::buy_execution(fees, weight_limit)),
RefundSurplus => sp_weights::Weight::from_ref_time(W::refund_surplus()),
SetErrorHandler(xcm) => sp_weights::Weight::from_ref_time(W::set_error_handler(xcm)),
SetAppendix(xcm) => sp_weights::Weight::from_ref_time(W::set_appendix(xcm)),
ClearError => sp_weights::Weight::from_ref_time(W::clear_error()),
ClaimAsset { assets, ticket } =>
sp_weights::Weight::from_ref_time(W::claim_asset(assets, ticket)),
Trap(code) => sp_weights::Weight::from_ref_time(W::trap(code)),
SubscribeVersion { query_id, max_response_weight } =>
W::subscribe_version(query_id, max_response_weight),
UnsubscribeVersion => W::unsubscribe_version(),
sp_weights::Weight::from_ref_time(W::subscribe_version(
query_id,
max_response_weight,
)),
UnsubscribeVersion => sp_weights::Weight::from_ref_time(W::unsubscribe_version()),
}
}
}
@@ -764,180 +998,130 @@ pub mod opaque {
pub type Instruction = super::Instruction<()>;
}
// Convert from a v1 response to a v2 response
impl TryFrom<OldResponse> for Response {
// Convert from a v3 response to a v2 response
impl TryFrom<NewResponse> for Response {
type Error = ();
fn try_from(old_response: OldResponse) -> result::Result<Self, ()> {
match old_response {
OldResponse::Assets(assets) => Ok(Self::Assets(assets)),
OldResponse::Version(version) => Ok(Self::Version(version)),
}
}
}
impl<RuntimeCall> TryFrom<OldXcm<RuntimeCall>> for Xcm<RuntimeCall> {
type Error = ();
fn try_from(old: OldXcm<RuntimeCall>) -> result::Result<Xcm<RuntimeCall>, ()> {
use Instruction::*;
Ok(Xcm(match old {
OldXcm::WithdrawAsset { assets, effects } => Some(Ok(WithdrawAsset(assets)))
.into_iter()
.chain(effects.into_iter().map(Instruction::try_from))
.collect::<result::Result<Vec<_>, _>>()?,
OldXcm::ReserveAssetDeposited { assets, effects } =>
Some(Ok(ReserveAssetDeposited(assets)))
.into_iter()
.chain(Some(Ok(ClearOrigin)).into_iter())
.chain(effects.into_iter().map(Instruction::try_from))
.collect::<result::Result<Vec<_>, _>>()?,
OldXcm::ReceiveTeleportedAsset { assets, effects } =>
Some(Ok(ReceiveTeleportedAsset(assets)))
.into_iter()
.chain(Some(Ok(ClearOrigin)).into_iter())
.chain(effects.into_iter().map(Instruction::try_from))
.collect::<result::Result<Vec<_>, _>>()?,
OldXcm::QueryResponse { query_id, response } => vec![QueryResponse {
query_id,
response: response.try_into()?,
max_weight: 50_000_000,
}],
OldXcm::TransferAsset { assets, beneficiary } =>
vec![TransferAsset { assets, beneficiary }],
OldXcm::TransferReserveAsset { assets, dest, effects } => vec![TransferReserveAsset {
assets,
dest,
xcm: Xcm(effects
.into_iter()
.map(Instruction::<()>::try_from)
.collect::<result::Result<_, _>>()?),
}],
OldXcm::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
vec![HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity }],
OldXcm::HrmpChannelAccepted { recipient } => vec![HrmpChannelAccepted { recipient }],
OldXcm::HrmpChannelClosing { initiator, sender, recipient } =>
vec![HrmpChannelClosing { initiator, sender, recipient }],
OldXcm::Transact { origin_type, require_weight_at_most, call } =>
vec![Transact { origin_type, require_weight_at_most, call }],
// We don't handle this one at all due to nested XCM.
OldXcm::RelayedFrom { .. } => return Err(()),
OldXcm::SubscribeVersion { query_id, max_response_weight } =>
vec![SubscribeVersion { query_id, max_response_weight }],
OldXcm::UnsubscribeVersion => vec![UnsubscribeVersion],
}))
}
}
impl<RuntimeCall> TryFrom<OldOrder<RuntimeCall>> for Instruction<RuntimeCall> {
type Error = ();
fn try_from(old: OldOrder<RuntimeCall>) -> result::Result<Instruction<RuntimeCall>, ()> {
use Instruction::*;
Ok(match old {
OldOrder::Noop => return Err(()),
OldOrder::DepositAsset { assets, max_assets, beneficiary } =>
DepositAsset { assets, max_assets, beneficiary },
OldOrder::DepositReserveAsset { assets, max_assets, dest, effects } =>
DepositReserveAsset {
assets,
max_assets,
dest,
xcm: Xcm(effects
.into_iter()
.map(Instruction::<()>::try_from)
.collect::<result::Result<_, _>>()?),
},
OldOrder::ExchangeAsset { give, receive } => ExchangeAsset { give, receive },
OldOrder::InitiateReserveWithdraw { assets, reserve, effects } =>
InitiateReserveWithdraw {
assets,
reserve,
xcm: Xcm(effects
.into_iter()
.map(Instruction::<()>::try_from)
.collect::<result::Result<_, _>>()?),
},
OldOrder::InitiateTeleport { assets, dest, effects } => InitiateTeleport {
assets,
dest,
xcm: Xcm(effects
.into_iter()
.map(Instruction::<()>::try_from)
.collect::<result::Result<_, _>>()?),
},
OldOrder::QueryHolding { query_id, dest, assets } =>
QueryHolding { query_id, dest, assets, max_response_weight: 0 },
OldOrder::BuyExecution { fees, debt, instructions, .. } => {
// We don't handle nested XCM.
if !instructions.is_empty() {
return Err(())
}
BuyExecution { fees, weight_limit: WeightLimit::Limited(debt) }
},
fn try_from(response: NewResponse) -> result::Result<Self, ()> {
Ok(match response {
NewResponse::Assets(assets) => Self::Assets(assets.try_into()?),
NewResponse::Version(version) => Self::Version(version),
NewResponse::ExecutionResult(error) => Self::ExecutionResult(match error {
Some((i, e)) => Some((i, e.try_into()?)),
None => None,
}),
NewResponse::Null => Self::Null,
_ => return Err(()),
})
}
}
#[cfg(test)]
mod tests {
use super::{prelude::*, *};
#[test]
fn basic_roundtrip_works() {
let xcm =
Xcm::<()>(vec![TransferAsset { assets: (Here, 1).into(), beneficiary: Here.into() }]);
let old_xcm =
OldXcm::<()>::TransferAsset { assets: (Here, 1).into(), beneficiary: Here.into() };
assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
assert_eq!(new_xcm, xcm);
}
#[test]
fn teleport_roundtrip_works() {
let xcm = Xcm::<()>(vec![
ReceiveTeleportedAsset((Here, 1).into()),
ClearOrigin,
DepositAsset { assets: Wild(All), max_assets: 1, beneficiary: Here.into() },
]);
let old_xcm: OldXcm<()> = OldXcm::<()>::ReceiveTeleportedAsset {
assets: (Here, 1).into(),
effects: vec![OldOrder::DepositAsset {
assets: Wild(All),
max_assets: 1,
beneficiary: Here.into(),
}],
};
assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
assert_eq!(new_xcm, xcm);
}
#[test]
fn reserve_deposit_roundtrip_works() {
let xcm = Xcm::<()>(vec![
ReserveAssetDeposited((Here, 1).into()),
ClearOrigin,
BuyExecution { fees: (Here, 1).into(), weight_limit: Some(1).into() },
DepositAsset { assets: Wild(All), max_assets: 1, beneficiary: Here.into() },
]);
let old_xcm: OldXcm<()> = OldXcm::<()>::ReserveAssetDeposited {
assets: (Here, 1).into(),
effects: vec![
OldOrder::BuyExecution {
fees: (Here, 1).into(),
debt: 1,
weight: 0,
instructions: vec![],
halt_on_error: true,
},
OldOrder::DepositAsset {
assets: Wild(All),
max_assets: 1,
beneficiary: Here.into(),
},
],
};
assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
assert_eq!(new_xcm, xcm);
// Convert from a v3 XCM to a v2 XCM.
impl<RuntimeCall> TryFrom<NewXcm<RuntimeCall>> for Xcm<RuntimeCall> {
type Error = ();
fn try_from(new_xcm: NewXcm<RuntimeCall>) -> result::Result<Self, ()> {
Ok(Xcm(new_xcm.0.into_iter().map(TryInto::try_into).collect::<result::Result<_, _>>()?))
}
}
// Convert from a v3 instruction to a v2 instruction
impl<RuntimeCall> TryFrom<NewInstruction<RuntimeCall>> for Instruction<RuntimeCall> {
type Error = ();
fn try_from(instruction: NewInstruction<RuntimeCall>) -> result::Result<Self, ()> {
use NewInstruction::*;
Ok(match instruction {
WithdrawAsset(assets) => Self::WithdrawAsset(assets.try_into()?),
ReserveAssetDeposited(assets) => Self::ReserveAssetDeposited(assets.try_into()?),
ReceiveTeleportedAsset(assets) => Self::ReceiveTeleportedAsset(assets.try_into()?),
QueryResponse { query_id, response, max_weight, .. } => Self::QueryResponse {
query_id,
response: response.try_into()?,
max_weight: max_weight.ref_time(),
},
TransferAsset { assets, beneficiary } => Self::TransferAsset {
assets: assets.try_into()?,
beneficiary: beneficiary.try_into()?,
},
TransferReserveAsset { assets, dest, xcm } => Self::TransferReserveAsset {
assets: assets.try_into()?,
dest: dest.try_into()?,
xcm: xcm.try_into()?,
},
HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
Self::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
HrmpChannelAccepted { recipient } => Self::HrmpChannelAccepted { recipient },
HrmpChannelClosing { initiator, sender, recipient } =>
Self::HrmpChannelClosing { initiator, sender, recipient },
Transact { origin_kind, require_weight_at_most, call } => Self::Transact {
origin_type: origin_kind,
require_weight_at_most: require_weight_at_most.ref_time(),
call: call.into(),
},
ReportError(response_info) => Self::ReportError {
query_id: response_info.query_id,
dest: response_info.destination.try_into()?,
max_response_weight: response_info.max_weight.ref_time(),
},
DepositAsset { assets, beneficiary } => {
let max_assets = assets.count().ok_or(())?;
let beneficiary = beneficiary.try_into()?;
let assets = assets.try_into()?;
Self::DepositAsset { assets, max_assets, beneficiary }
},
DepositReserveAsset { assets, dest, xcm } => {
let max_assets = assets.count().ok_or(())?;
let dest = dest.try_into()?;
let xcm = xcm.try_into()?;
let assets = assets.try_into()?;
Self::DepositReserveAsset { assets, max_assets, dest, xcm }
},
ExchangeAsset { give, want, .. } => {
let give = give.try_into()?;
let receive = want.try_into()?;
Self::ExchangeAsset { give, receive }
},
InitiateReserveWithdraw { assets, reserve, xcm } => {
// No `max_assets` here, so if there's a connt, then we cannot translate.
let assets = assets.try_into()?;
let reserve = reserve.try_into()?;
let xcm = xcm.try_into()?;
Self::InitiateReserveWithdraw { assets, reserve, xcm }
},
InitiateTeleport { assets, dest, xcm } => {
// No `max_assets` here, so if there's a connt, then we cannot translate.
let assets = assets.try_into()?;
let dest = dest.try_into()?;
let xcm = xcm.try_into()?;
Self::InitiateTeleport { assets, dest, xcm }
},
ReportHolding { response_info, assets } => Self::QueryHolding {
query_id: response_info.query_id,
dest: response_info.destination.try_into()?,
assets: assets.try_into()?,
max_response_weight: response_info.max_weight.ref_time(),
},
BuyExecution { fees, weight_limit } => {
let fees = fees.try_into()?;
let weight_limit = weight_limit.try_into()?;
Self::BuyExecution { fees, weight_limit }
},
ClearOrigin => Self::ClearOrigin,
DescendOrigin(who) => Self::DescendOrigin(who.try_into()?),
RefundSurplus => Self::RefundSurplus,
SetErrorHandler(xcm) => Self::SetErrorHandler(xcm.try_into()?),
SetAppendix(xcm) => Self::SetAppendix(xcm.try_into()?),
ClearError => Self::ClearError,
ClaimAsset { assets, ticket } => {
let assets = assets.try_into()?;
let ticket = ticket.try_into()?;
Self::ClaimAsset { assets, ticket }
},
Trap(code) => Self::Trap(code),
SubscribeVersion { query_id, max_response_weight } => Self::SubscribeVersion {
query_id,
max_response_weight: max_response_weight.ref_time(),
},
UnsubscribeVersion => Self::UnsubscribeVersion,
_ => return Err(()),
})
}
}
+608
View File
@@ -0,0 +1,608 @@
// Copyright 2020 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/>.
//! Cross-Consensus Message format asset data structures.
//!
//! This encompasses four types for representing assets:
//! - `MultiAsset`: A description of a single asset, either an instance of a non-fungible or some amount of a fungible.
//! - `MultiAssets`: A collection of `MultiAsset`s. These are stored in a `Vec` and sorted with fungibles first.
//! - `Wild`: A single asset wildcard, this can either be "all" assets, or all assets of a specific kind.
//! - `MultiAssetFilter`: A combination of `Wild` and `MultiAssets` designed for efficiently filtering an XCM holding
//! account.
use super::MultiLocation;
use crate::v3::{
AssetId as NewAssetId, AssetInstance as NewAssetInstance, Fungibility as NewFungibility,
MultiAsset as NewMultiAsset, MultiAssetFilter as NewMultiAssetFilter,
MultiAssets as NewMultiAssets, WildFungibility as NewWildFungibility,
WildMultiAsset as NewWildMultiAsset,
};
use alloc::{vec, vec::Vec};
use core::cmp::Ordering;
use parity_scale_codec::{self as codec, Decode, Encode};
use scale_info::TypeInfo;
/// A general identifier for an instance of a non-fungible asset class.
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo)]
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub enum AssetInstance {
/// Undefined - used if the non-fungible asset class has only one instance.
Undefined,
/// A compact index. Technically this could be greater than `u128`, but this implementation supports only
/// values up to `2**128 - 1`.
Index(#[codec(compact)] u128),
/// A 4-byte fixed-length datum.
Array4([u8; 4]),
/// An 8-byte fixed-length datum.
Array8([u8; 8]),
/// A 16-byte fixed-length datum.
Array16([u8; 16]),
/// A 32-byte fixed-length datum.
Array32([u8; 32]),
/// An arbitrary piece of data. Use only when necessary.
Blob(Vec<u8>),
}
impl From<()> for AssetInstance {
fn from(_: ()) -> Self {
Self::Undefined
}
}
impl From<[u8; 4]> for AssetInstance {
fn from(x: [u8; 4]) -> Self {
Self::Array4(x)
}
}
impl From<[u8; 8]> for AssetInstance {
fn from(x: [u8; 8]) -> Self {
Self::Array8(x)
}
}
impl From<[u8; 16]> for AssetInstance {
fn from(x: [u8; 16]) -> Self {
Self::Array16(x)
}
}
impl From<[u8; 32]> for AssetInstance {
fn from(x: [u8; 32]) -> Self {
Self::Array32(x)
}
}
impl From<Vec<u8>> for AssetInstance {
fn from(x: Vec<u8>) -> Self {
Self::Blob(x)
}
}
impl TryFrom<NewAssetInstance> for AssetInstance {
type Error = ();
fn try_from(value: NewAssetInstance) -> Result<Self, Self::Error> {
use NewAssetInstance::*;
Ok(match value {
Undefined => Self::Undefined,
Index(n) => Self::Index(n),
Array4(n) => Self::Array4(n),
Array8(n) => Self::Array8(n),
Array16(n) => Self::Array16(n),
Array32(n) => Self::Array32(n),
})
}
}
/// Classification of an asset being concrete or abstract.
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)]
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub enum AssetId {
Concrete(MultiLocation),
Abstract(Vec<u8>),
}
impl<T: Into<MultiLocation>> From<T> for AssetId {
fn from(x: T) -> Self {
Self::Concrete(x.into())
}
}
impl From<Vec<u8>> for AssetId {
fn from(x: Vec<u8>) -> Self {
Self::Abstract(x)
}
}
impl TryFrom<NewAssetId> for AssetId {
type Error = ();
fn try_from(old: NewAssetId) -> Result<Self, ()> {
use NewAssetId::*;
Ok(match old {
Concrete(l) => Self::Concrete(l.try_into()?),
Abstract(v) => {
let zeroes = v.iter().rev().position(|n| *n != 0).unwrap_or(v.len());
Self::Abstract(v[0..(32 - zeroes)].to_vec())
},
})
}
}
impl AssetId {
/// Prepend a `MultiLocation` to a concrete asset, giving it a new root location.
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 }
}
/// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding `WildMultiAsset`
/// wildcard (`AllOf`) value.
pub fn into_wild(self, fun: WildFungibility) -> WildMultiAsset {
WildMultiAsset::AllOf { fun, id: self }
}
}
/// Classification of whether an asset is fungible or not, along with a mandatory amount or instance.
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)]
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub enum Fungibility {
Fungible(#[codec(compact)] u128),
NonFungible(AssetInstance),
}
impl Fungibility {
pub fn is_kind(&self, w: WildFungibility) -> bool {
use Fungibility::*;
use WildFungibility::{Fungible as WildFungible, NonFungible as WildNonFungible};
matches!((self, w), (Fungible(_), WildFungible) | (NonFungible(_), WildNonFungible))
}
}
impl From<u128> for Fungibility {
fn from(amount: u128) -> Fungibility {
debug_assert_ne!(amount, 0);
Fungibility::Fungible(amount)
}
}
impl<T: Into<AssetInstance>> From<T> for Fungibility {
fn from(instance: T) -> Fungibility {
Fungibility::NonFungible(instance.into())
}
}
impl TryFrom<NewFungibility> for Fungibility {
type Error = ();
fn try_from(value: NewFungibility) -> Result<Self, Self::Error> {
use NewFungibility::*;
Ok(match value {
Fungible(n) => Self::Fungible(n),
NonFungible(i) => Self::NonFungible(i.try_into()?),
})
}
}
#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, TypeInfo)]
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub struct MultiAsset {
pub id: AssetId,
pub fun: Fungibility,
}
impl PartialOrd for MultiAsset {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for MultiAsset {
fn cmp(&self, other: &Self) -> Ordering {
match (&self.fun, &other.fun) {
(Fungibility::Fungible(..), Fungibility::NonFungible(..)) => Ordering::Less,
(Fungibility::NonFungible(..), Fungibility::Fungible(..)) => Ordering::Greater,
_ => (&self.id, &self.fun).cmp(&(&other.id, &other.fun)),
}
}
}
impl<A: Into<AssetId>, B: Into<Fungibility>> From<(A, B)> for MultiAsset {
fn from((id, fun): (A, B)) -> MultiAsset {
MultiAsset { fun: fun.into(), id: id.into() }
}
}
impl MultiAsset {
pub fn is_fungible(&self, maybe_id: Option<AssetId>) -> bool {
use Fungibility::*;
matches!(self.fun, Fungible(..)) && maybe_id.map_or(true, |i| i == self.id)
}
pub fn is_non_fungible(&self, maybe_id: Option<AssetId>) -> bool {
use Fungibility::*;
matches!(self.fun, NonFungible(..)) && maybe_id.map_or(true, |i| i == self.id)
}
/// Prepend a `MultiLocation` to a concrete asset, giving it a new root location.
pub fn prepend_with(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
self.id.prepend_with(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)
}
/// Returns true if `self` is a super-set of the given `inner`.
pub fn contains(&self, inner: &MultiAsset) -> bool {
use Fungibility::*;
if self.id == inner.id {
match (&self.fun, &inner.fun) {
(Fungible(a), Fungible(i)) if a >= i => return true,
(NonFungible(a), NonFungible(i)) if a == i => return true,
_ => (),
}
}
false
}
}
impl TryFrom<NewMultiAsset> for MultiAsset {
type Error = ();
fn try_from(new: NewMultiAsset) -> Result<Self, ()> {
Ok(Self { id: new.id.try_into()?, fun: new.fun.try_into()? })
}
}
/// A `Vec` of `MultiAsset`s. There may be no duplicate fungible items in here and when decoding, they must be sorted.
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, TypeInfo)]
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub struct MultiAssets(Vec<MultiAsset>);
impl Decode for MultiAssets {
fn decode<I: codec::Input>(input: &mut I) -> Result<Self, parity_scale_codec::Error> {
Self::from_sorted_and_deduplicated(Vec::<MultiAsset>::decode(input)?)
.map_err(|()| "Out of order".into())
}
}
impl TryFrom<NewMultiAssets> for MultiAssets {
type Error = ();
fn try_from(new: NewMultiAssets) -> Result<Self, ()> {
let v = new
.into_inner()
.into_iter()
.map(MultiAsset::try_from)
.collect::<Result<Vec<_>, ()>>()?;
Ok(MultiAssets(v))
}
}
impl From<Vec<MultiAsset>> for MultiAssets {
fn from(mut assets: Vec<MultiAsset>) -> Self {
let mut res = Vec::with_capacity(assets.len());
if !assets.is_empty() {
assets.sort();
let mut iter = assets.into_iter();
if let Some(first) = iter.next() {
let last = iter.fold(first, |a, b| -> MultiAsset {
match (a, b) {
(
MultiAsset { fun: Fungibility::Fungible(a_amount), id: a_id },
MultiAsset { fun: Fungibility::Fungible(b_amount), id: b_id },
) if a_id == b_id => MultiAsset {
id: a_id,
fun: Fungibility::Fungible(a_amount.saturating_add(b_amount)),
},
(
MultiAsset { fun: Fungibility::NonFungible(a_instance), id: a_id },
MultiAsset { fun: Fungibility::NonFungible(b_instance), id: b_id },
) if a_id == b_id && a_instance == b_instance =>
MultiAsset { fun: Fungibility::NonFungible(a_instance), id: a_id },
(to_push, to_remember) => {
res.push(to_push);
to_remember
},
}
});
res.push(last);
}
}
Self(res)
}
}
impl<T: Into<MultiAsset>> From<T> for MultiAssets {
fn from(x: T) -> Self {
Self(vec![x.into()])
}
}
impl MultiAssets {
/// A new (empty) value.
pub fn new() -> Self {
Self(Vec::new())
}
/// Create a new instance of `MultiAssets` from a `Vec<MultiAsset>` whose contents are sorted and
/// which contain no duplicates.
///
/// Returns `Ok` if the operation succeeds and `Err` if `r` is out of order or had duplicates. If you can't
/// guarantee that `r` is sorted and deduplicated, then use `From::<Vec<MultiAsset>>::from` which is infallible.
pub fn from_sorted_and_deduplicated(r: Vec<MultiAsset>) -> Result<Self, ()> {
if r.is_empty() {
return Ok(Self(Vec::new()))
}
r.iter().skip(1).try_fold(&r[0], |a, b| -> Result<&MultiAsset, ()> {
if a.id < b.id || a < b && (a.is_non_fungible(None) || b.is_non_fungible(None)) {
Ok(b)
} else {
Err(())
}
})?;
Ok(Self(r))
}
/// Create a new instance of `MultiAssets` from a `Vec<MultiAsset>` whose contents are sorted and
/// which contain no duplicates.
///
/// In release mode, this skips any checks to ensure that `r` is correct, making it a negligible-cost operation.
/// Generally though you should avoid using it unless you have a strict proof that `r` is valid.
#[cfg(test)]
pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<MultiAsset>) -> Self {
Self::from_sorted_and_deduplicated(r).expect("Invalid input r is not sorted/deduped")
}
/// Create a new instance of `MultiAssets` from a `Vec<MultiAsset>` whose contents are sorted and
/// which contain no duplicates.
///
/// In release mode, this skips any checks to ensure that `r` is correct, making it a negligible-cost operation.
/// Generally though you should avoid using it unless you have a strict proof that `r` is valid.
///
/// In test mode, this checks anyway and panics on fail.
#[cfg(not(test))]
pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<MultiAsset>) -> Self {
Self(r)
}
/// Add some asset onto the list, saturating. This is quite a laborious operation since it maintains the ordering.
pub fn push(&mut self, a: MultiAsset) {
if let Fungibility::Fungible(ref amount) = a.fun {
for asset in self.0.iter_mut().filter(|x| x.id == a.id) {
if let Fungibility::Fungible(ref mut balance) = asset.fun {
*balance = balance.saturating_add(*amount);
return
}
}
}
self.0.push(a);
self.0.sort();
}
/// Returns `true` if this definitely represents no asset.
pub fn is_none(&self) -> bool {
self.0.is_empty()
}
/// Returns true if `self` is a super-set of the given `inner`.
pub fn contains(&self, inner: &MultiAsset) -> bool {
self.0.iter().any(|i| i.contains(inner))
}
/// Consume `self` and return the inner vec.
pub fn drain(self) -> Vec<MultiAsset> {
self.0
}
/// Return a reference to the inner vec.
pub fn inner(&self) -> &Vec<MultiAsset> {
&self.0
}
/// Return the number of distinct asset instances contained.
pub fn len(&self) -> usize {
self.0.len()
}
/// Prepend a `MultiLocation` to any concrete asset items, giving it a new root location.
pub fn prepend_with(&mut self, prefix: &MultiLocation) -> Result<(), ()> {
self.0.iter_mut().try_for_each(|i| i.prepend_with(prefix))
}
/// 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.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.
pub fn get(&self, index: usize) -> Option<&MultiAsset> {
self.0.get(index)
}
}
/// Classification of whether an asset is fungible or not.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)]
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub enum WildFungibility {
Fungible,
NonFungible,
}
impl TryFrom<NewWildFungibility> for WildFungibility {
type Error = ();
fn try_from(value: NewWildFungibility) -> Result<Self, Self::Error> {
use NewWildFungibility::*;
Ok(match value {
Fungible => Self::Fungible,
NonFungible => Self::NonFungible,
})
}
}
/// A wildcard representing a set of assets.
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)]
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub enum WildMultiAsset {
/// All assets in the holding register, up to `usize` individual assets (different instances of non-fungibles could
/// be separate assets).
All,
/// All assets in the holding register of a given fungibility and ID. If operating on non-fungibles, then a limit
/// is provided for the maximum amount of matching instances.
AllOf { id: AssetId, fun: WildFungibility },
}
impl WildMultiAsset {
/// 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 WildMultiAsset::*;
match self {
AllOf { fun, id } => inner.fun.is_kind(*fun) && &inner.id == id,
All => true,
}
}
/// 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<(), ()> {
use WildMultiAsset::*;
match self {
AllOf { ref mut id, .. } => id.reanchor(target, ancestry).map_err(|_| ()),
All => Ok(()),
}
}
}
impl<A: Into<AssetId>, B: Into<WildFungibility>> From<(A, B)> for WildMultiAsset {
fn from((id, fun): (A, B)) -> WildMultiAsset {
WildMultiAsset::AllOf { fun: fun.into(), id: id.into() }
}
}
/// `MultiAsset` collection, either `MultiAssets` or a single wildcard.
///
/// Note: Vectors of wildcards whose encoding is supported in XCM v0 are unsupported
/// in this implementation and will result in a decode error.
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)]
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub enum MultiAssetFilter {
Definite(MultiAssets),
Wild(WildMultiAsset),
}
impl<T: Into<WildMultiAsset>> From<T> for MultiAssetFilter {
fn from(x: T) -> Self {
Self::Wild(x.into())
}
}
impl From<MultiAsset> for MultiAssetFilter {
fn from(x: MultiAsset) -> Self {
Self::Definite(vec![x].into())
}
}
impl From<Vec<MultiAsset>> for MultiAssetFilter {
fn from(x: Vec<MultiAsset>) -> Self {
Self::Definite(x.into())
}
}
impl From<MultiAssets> for MultiAssetFilter {
fn from(x: MultiAssets) -> Self {
Self::Definite(x)
}
}
impl MultiAssetFilter {
/// 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 {
match self {
MultiAssetFilter::Definite(ref assets) => assets.contains(inner),
MultiAssetFilter::Wild(ref wild) => wild.contains(inner),
}
}
/// 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<(), ()> {
match self {
MultiAssetFilter::Definite(ref mut assets) => assets.reanchor(target, ancestry),
MultiAssetFilter::Wild(ref mut wild) => wild.reanchor(target, ancestry),
}
}
}
impl TryFrom<NewWildMultiAsset> for WildMultiAsset {
type Error = ();
fn try_from(new: NewWildMultiAsset) -> Result<Self, ()> {
use NewWildMultiAsset::*;
Ok(match new {
AllOf { id, fun } | AllOfCounted { id, fun, .. } =>
Self::AllOf { id: id.try_into()?, fun: fun.try_into()? },
All | AllCounted(_) => Self::All,
})
}
}
impl TryFrom<NewMultiAssetFilter> for MultiAssetFilter {
type Error = ();
fn try_from(old: NewMultiAssetFilter) -> Result<Self, ()> {
use NewMultiAssetFilter::*;
Ok(match old {
Definite(x) => Self::Definite(x.try_into()?),
Wild(x) => Self::Wild(x.try_into()?),
})
}
}
File diff suppressed because it is too large Load Diff
+41 -8
View File
@@ -16,6 +16,7 @@
//! Cross-Consensus Message format data structures.
use crate::v3::Error as NewError;
use core::result;
use parity_scale_codec::{Decode, Encode};
use scale_info::TypeInfo;
@@ -110,10 +111,42 @@ pub enum Error {
WeightNotComputable,
}
impl TryFrom<NewError> for Error {
type Error = ();
fn try_from(new_error: NewError) -> result::Result<Error, ()> {
use NewError::*;
Ok(match new_error {
Overflow => Self::Overflow,
Unimplemented => Self::Unimplemented,
UntrustedReserveLocation => Self::UntrustedReserveLocation,
UntrustedTeleportLocation => Self::UntrustedTeleportLocation,
LocationFull => Self::MultiLocationFull,
LocationNotInvertible => Self::MultiLocationNotInvertible,
BadOrigin => Self::BadOrigin,
InvalidLocation => Self::InvalidLocation,
AssetNotFound => Self::AssetNotFound,
FailedToTransactAsset(s) => Self::FailedToTransactAsset(s),
NotWithdrawable => Self::NotWithdrawable,
LocationCannotHold => Self::LocationCannotHold,
ExceedsMaxMessageSize => Self::ExceedsMaxMessageSize,
DestinationUnsupported => Self::DestinationUnsupported,
Transport(s) => Self::Transport(s),
Unroutable => Self::Unroutable,
UnknownClaim => Self::UnknownClaim,
FailedToDecode => Self::FailedToDecode,
MaxWeightInvalid => Self::MaxWeightInvalid,
NotHoldingFees => Self::NotHoldingFees,
TooExpensive => Self::TooExpensive,
Trap(i) => Self::Trap(i),
_ => return Err(()),
})
}
}
impl From<SendError> for Error {
fn from(e: SendError) -> Self {
match e {
SendError::CannotReachDestination(..) | SendError::Unroutable => Error::Unroutable,
SendError::NotApplicable(..) | SendError::Unroutable => Error::Unroutable,
SendError::Transport(s) => Error::Transport(s),
SendError::DestinationUnsupported => Error::DestinationUnsupported,
SendError::ExceedsMaxMessageSize => Error::ExceedsMaxMessageSize,
@@ -210,7 +243,7 @@ pub enum SendError {
///
/// This is not considered fatal: if there are alternative transport routes available, then
/// they may be attempted. For this reason, the destination and message are contained.
CannotReachDestination(MultiLocation, Xcm<()>),
NotApplicable(MultiLocation, Xcm<()>),
/// Destination is routable, but there is some issue with the transport mechanism. This is
/// considered fatal.
/// A human-readable explanation of the specific issue is provided.
@@ -231,7 +264,7 @@ pub type SendResult = result::Result<(), SendError>;
/// Utility for sending an XCM message.
///
/// These can be amalgamated in tuples to form sophisticated routing systems. In tuple format, each router might return
/// `CannotReachDestination` to pass the execution to the next sender item. Note that each `CannotReachDestination`
/// `NotApplicable` to pass the execution to the next sender item. Note that each `NotApplicable`
/// might alter the destination and the XCM message for to the next router.
///
///
@@ -244,7 +277,7 @@ pub type SendResult = result::Result<(), SendError>;
/// struct Sender1;
/// impl SendXcm for Sender1 {
/// fn send_xcm(destination: impl Into<MultiLocation>, message: Xcm<()>) -> SendResult {
/// return Err(SendError::CannotReachDestination(destination.into(), message))
/// return Err(SendError::NotApplicable(destination.into(), message))
/// }
/// }
///
@@ -267,7 +300,7 @@ pub type SendResult = result::Result<(), SendError>;
/// let destination = destination.into();
/// match destination {
/// MultiLocation { parents: 1, interior: Here } => Ok(()),
/// _ => Err(SendError::CannotReachDestination(destination, message)),
/// _ => Err(SendError::NotApplicable(destination, message)),
/// }
/// }
/// }
@@ -298,7 +331,7 @@ pub trait SendXcm {
/// Send an XCM `message` to a given `destination`.
///
/// If it is not a destination which can be reached with this type but possibly could by others, then it *MUST*
/// return `CannotReachDestination`. Any other error will cause the tuple implementation to exit early without
/// return `NotApplicable`. Any other error will cause the tuple implementation to exit early without
/// trying other type fields.
fn send_xcm(destination: impl Into<MultiLocation>, message: Xcm<()>) -> SendResult;
}
@@ -309,10 +342,10 @@ impl SendXcm for Tuple {
for_tuples!( #(
// we shadow `destination` and `message` in each expansion for the next one.
let (destination, message) = match Tuple::send_xcm(destination, message) {
Err(SendError::CannotReachDestination(d, m)) => (d, m),
Err(SendError::NotApplicable(d, m)) => (d, m),
o @ _ => return o,
};
)* );
Err(SendError::CannotReachDestination(destination.into(), message))
Err(SendError::NotApplicable(destination.into(), message))
}
}