mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-09 04:47:59 +00:00
XCM v3 (#4097)
* 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:
Generated
+218
-191
File diff suppressed because it is too large
Load Diff
@@ -354,7 +354,7 @@ async fn run(
|
||||
futures::select_biased! {
|
||||
() = cleanup_pulse.select_next_some() => {
|
||||
// `select_next_some` because we don't expect this to fail, but if it does, we
|
||||
// still don't fail. The tradeoff is that the compiled cache will start growing
|
||||
// still don't fail. The trade-off is that the compiled cache will start growing
|
||||
// in size. That is, however, rather a slow process and hopefully the operator
|
||||
// will notice it.
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ const STATEMENTS_TIMEOUT: Duration = Duration::from_secs(1);
|
||||
|
||||
/// We don't want a slow peer to slow down all the others, at the same time we want to get out the
|
||||
/// data quickly in full to at least some peers (as this will reduce load on us as they then can
|
||||
/// start serving the data). So this value is a tradeoff. 3 seems to be sensible. So we would need
|
||||
/// start serving the data). So this value is a trade-off. 3 seems to be sensible. So we would need
|
||||
/// to have 3 slow nodes connected, to delay transfer for others by `STATEMENTS_TIMEOUT`.
|
||||
pub const MAX_PARALLEL_STATEMENT_REQUESTS: u32 = 3;
|
||||
|
||||
|
||||
@@ -189,8 +189,7 @@ fn default_parachains_host_configuration(
|
||||
max_upward_queue_count: 8,
|
||||
max_upward_queue_size: 1024 * 1024,
|
||||
max_downward_message_size: 1024 * 1024,
|
||||
ump_service_total_weight: Weight::from_ref_time(100_000_000_000)
|
||||
.set_proof_size(MAX_POV_SIZE as u64),
|
||||
ump_service_total_weight: Weight::from_parts(100_000_000_000, MAX_POV_SIZE as u64),
|
||||
max_upward_message_size: 50 * 1024,
|
||||
max_upward_message_num_per_candidate: 5,
|
||||
hrmp_sender_deposit: 0,
|
||||
|
||||
@@ -138,7 +138,7 @@ mod tests {
|
||||
weight.base_extrinsic = Weight::from_ref_time(100);
|
||||
})
|
||||
.for_class(DispatchClass::non_mandatory(), |weight| {
|
||||
weight.max_total = Some(Weight::from_ref_time(1024).set_proof_size(u64::MAX));
|
||||
weight.max_total = Some(Weight::from_parts(1024, u64::MAX));
|
||||
})
|
||||
.build_or_panic();
|
||||
pub BlockLength: limits::BlockLength = limits::BlockLength::max(2 * 1024);
|
||||
|
||||
@@ -103,7 +103,7 @@ parameter_types! {
|
||||
pub const BlockHashCount: u32 = 250;
|
||||
pub BlockWeights: frame_system::limits::BlockWeights =
|
||||
frame_system::limits::BlockWeights::simple_max(
|
||||
Weight::from_ref_time(4 * 1024 * 1024).set_proof_size(u64::MAX),
|
||||
Weight::from_parts(4 * 1024 * 1024, u64::MAX),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -705,9 +705,7 @@ mod tests {
|
||||
parameter_types! {
|
||||
pub const BlockHashCount: u32 = 250;
|
||||
pub BlockWeights: limits::BlockWeights =
|
||||
frame_system::limits::BlockWeights::simple_max(
|
||||
Weight::from_ref_time(1024).set_proof_size(u64::MAX),
|
||||
);
|
||||
frame_system::limits::BlockWeights::simple_max(Weight::from_parts(1024, u64::MAX));
|
||||
pub BlockLength: limits::BlockLength =
|
||||
limits::BlockLength::max_with_normal_ratio(4 * 1024 * 1024, NORMAL_RATIO);
|
||||
}
|
||||
|
||||
@@ -16,34 +16,75 @@
|
||||
|
||||
//! XCM sender for relay chain.
|
||||
|
||||
use frame_support::traits::Get;
|
||||
use parity_scale_codec::Encode;
|
||||
use runtime_parachains::{configuration, dmp};
|
||||
use sp_std::marker::PhantomData;
|
||||
use xcm::latest::prelude::*;
|
||||
use primitives::v2::Id as ParaId;
|
||||
use runtime_parachains::{
|
||||
configuration::{self, HostConfiguration},
|
||||
dmp,
|
||||
};
|
||||
use sp_std::{marker::PhantomData, prelude::*};
|
||||
use xcm::prelude::*;
|
||||
use SendError::*;
|
||||
|
||||
/// XCM sender for relay chain. It only sends downward message.
|
||||
pub struct ChildParachainRouter<T, W>(PhantomData<(T, W)>);
|
||||
|
||||
impl<T: configuration::Config + dmp::Config, W: xcm::WrapVersion> SendXcm
|
||||
for ChildParachainRouter<T, W>
|
||||
{
|
||||
fn send_xcm(dest: impl Into<MultiLocation>, msg: Xcm<()>) -> SendResult {
|
||||
let dest = dest.into();
|
||||
match dest {
|
||||
MultiLocation { parents: 0, interior: X1(Parachain(id)) } => {
|
||||
// Downward message passing.
|
||||
let versioned_xcm =
|
||||
W::wrap_version(&dest, msg).map_err(|()| SendError::DestinationUnsupported)?;
|
||||
let config = <configuration::Pallet<T>>::config();
|
||||
<dmp::Pallet<T>>::queue_downward_message(
|
||||
&config,
|
||||
id.into(),
|
||||
versioned_xcm.encode(),
|
||||
)
|
||||
.map_err(Into::<SendError>::into)?;
|
||||
Ok(())
|
||||
},
|
||||
dest => Err(SendError::CannotReachDestination(dest, msg)),
|
||||
}
|
||||
/// Simple value-bearing trait for determining/expressing the assets required to be paid for a
|
||||
/// messages to be delivered to a parachain.
|
||||
pub trait PriceForParachainDelivery {
|
||||
/// Return the assets required to deliver `message` to the given `para` destination.
|
||||
fn price_for_parachain_delivery(para: ParaId, message: &Xcm<()>) -> MultiAssets;
|
||||
}
|
||||
impl PriceForParachainDelivery for () {
|
||||
fn price_for_parachain_delivery(_: ParaId, _: &Xcm<()>) -> MultiAssets {
|
||||
MultiAssets::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of `PriceForParachainDelivery` which returns a fixed price.
|
||||
pub struct ConstantPrice<T>(sp_std::marker::PhantomData<T>);
|
||||
impl<T: Get<MultiAssets>> PriceForParachainDelivery for ConstantPrice<T> {
|
||||
fn price_for_parachain_delivery(_: ParaId, _: &Xcm<()>) -> MultiAssets {
|
||||
T::get()
|
||||
}
|
||||
}
|
||||
|
||||
/// XCM sender for relay chain. It only sends downward message.
|
||||
pub struct ChildParachainRouter<T, W, P>(PhantomData<(T, W, P)>);
|
||||
|
||||
impl<T: configuration::Config + dmp::Config, W: xcm::WrapVersion, P: PriceForParachainDelivery>
|
||||
SendXcm for ChildParachainRouter<T, W, P>
|
||||
{
|
||||
type Ticket = (HostConfiguration<T::BlockNumber>, ParaId, Vec<u8>);
|
||||
|
||||
fn validate(
|
||||
dest: &mut Option<MultiLocation>,
|
||||
msg: &mut Option<Xcm<()>>,
|
||||
) -> SendResult<(HostConfiguration<T::BlockNumber>, ParaId, Vec<u8>)> {
|
||||
let d = dest.take().ok_or(MissingArgument)?;
|
||||
let id = if let MultiLocation { parents: 0, interior: X1(Parachain(id)) } = &d {
|
||||
*id
|
||||
} else {
|
||||
*dest = Some(d);
|
||||
return Err(NotApplicable)
|
||||
};
|
||||
|
||||
// Downward message passing.
|
||||
let xcm = msg.take().ok_or(MissingArgument)?;
|
||||
let config = <configuration::Pallet<T>>::config();
|
||||
let para = id.into();
|
||||
let price = P::price_for_parachain_delivery(para, &xcm);
|
||||
let blob = W::wrap_version(&d, xcm).map_err(|()| DestinationUnsupported)?.encode();
|
||||
<dmp::Pallet<T>>::can_queue_downward_message(&config, ¶, &blob)
|
||||
.map_err(Into::<SendError>::into)?;
|
||||
|
||||
Ok(((config, para, blob), price))
|
||||
}
|
||||
|
||||
fn deliver(
|
||||
(config, para, blob): (HostConfiguration<T::BlockNumber>, ParaId, Vec<u8>),
|
||||
) -> Result<XcmHash, SendError> {
|
||||
let hash = sp_io::hashing::blake2_256(&blob[..]);
|
||||
<dmp::Pallet<T>>::queue_downward_message(&config, para, blob)
|
||||
.map(|()| hash)
|
||||
.map_err(|_| SendError::Transport(&"Error placing into DMP queue"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1497,6 +1497,9 @@ pub type Migrations = (
|
||||
pallet_staking::migrations::v13::MigrateToV13<Runtime>,
|
||||
parachains_disputes::migration::v1::MigrateToV1<Runtime>,
|
||||
parachains_configuration::migration::v4::MigrateToV4<Runtime>,
|
||||
// "Use 2D weights in XCM v3" <https://github.com/paritytech/polkadot/pull/6134>
|
||||
pallet_xcm::migration::v1::MigrateToV1<Runtime>,
|
||||
parachains_ump::migration::v1::MigrateToV1<Runtime>,
|
||||
);
|
||||
|
||||
/// Unchecked extrinsic type as expected by this runtime.
|
||||
@@ -1576,6 +1579,7 @@ mod benches {
|
||||
[pallet_vesting, Vesting]
|
||||
[pallet_whitelist, Whitelist]
|
||||
// XCM
|
||||
[pallet_xcm, XcmPallet]
|
||||
[pallet_xcm_benchmarks::fungible, pallet_xcm_benchmarks::fungible::Pallet::<Runtime>]
|
||||
[pallet_xcm_benchmarks::generic, pallet_xcm_benchmarks::generic::Pallet::<Runtime>]
|
||||
);
|
||||
@@ -1978,7 +1982,9 @@ sp_api::impl_runtime_apis! {
|
||||
use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench;
|
||||
use frame_benchmarking::baseline::Pallet as Baseline;
|
||||
use xcm::latest::prelude::*;
|
||||
use xcm_config::{CheckAccount, KsmLocation, SovereignAccountOf, Statemine, XcmConfig};
|
||||
use xcm_config::{
|
||||
LocalCheckAccount, SovereignAccountOf, Statemine, TokenLocation, XcmConfig,
|
||||
};
|
||||
|
||||
impl pallet_session_benchmarking::Config for Runtime {}
|
||||
impl pallet_offences_benchmarking::Config for Runtime {}
|
||||
@@ -1993,10 +1999,10 @@ sp_api::impl_runtime_apis! {
|
||||
fn valid_destination() -> Result<MultiLocation, BenchmarkError> {
|
||||
Ok(Statemine::get())
|
||||
}
|
||||
fn worst_case_holding() -> MultiAssets {
|
||||
fn worst_case_holding(_depositable_count: u32) -> MultiAssets {
|
||||
// Kusama only knows about KSM.
|
||||
vec![MultiAsset{
|
||||
id: Concrete(KsmLocation::get()),
|
||||
id: Concrete(TokenLocation::get()),
|
||||
fun: Fungible(1_000_000 * UNITS),
|
||||
}].into()
|
||||
}
|
||||
@@ -2005,24 +2011,19 @@ sp_api::impl_runtime_apis! {
|
||||
parameter_types! {
|
||||
pub const TrustedTeleporter: Option<(MultiLocation, MultiAsset)> = Some((
|
||||
Statemine::get(),
|
||||
MultiAsset { fun: Fungible(1 * UNITS), id: Concrete(KsmLocation::get()) },
|
||||
));
|
||||
pub const TrustedReserve: Option<(MultiLocation, MultiAsset)> = Some((
|
||||
Statemine::get(),
|
||||
MultiAsset { fun: Fungible(1 * UNITS), id: Concrete(KsmLocation::get()) },
|
||||
MultiAsset { fun: Fungible(1 * UNITS), id: Concrete(TokenLocation::get()) },
|
||||
));
|
||||
}
|
||||
|
||||
impl pallet_xcm_benchmarks::fungible::Config for Runtime {
|
||||
type TransactAsset = Balances;
|
||||
|
||||
type CheckedAccount = CheckAccount;
|
||||
type CheckedAccount = LocalCheckAccount;
|
||||
type TrustedTeleporter = TrustedTeleporter;
|
||||
type TrustedReserve = TrustedReserve;
|
||||
|
||||
fn get_multi_asset() -> MultiAsset {
|
||||
MultiAsset {
|
||||
id: Concrete(KsmLocation::get()),
|
||||
id: Concrete(TokenLocation::get()),
|
||||
fun: Fungible(1 * UNITS),
|
||||
}
|
||||
}
|
||||
@@ -2035,8 +2036,18 @@ sp_api::impl_runtime_apis! {
|
||||
(0u64, Response::Version(Default::default()))
|
||||
}
|
||||
|
||||
fn transact_origin() -> Result<MultiLocation, BenchmarkError> {
|
||||
Ok(Statemine::get())
|
||||
fn worst_case_asset_exchange() -> Result<(MultiAssets, MultiAssets), BenchmarkError> {
|
||||
// Kusama doesn't support asset exchanges
|
||||
Err(BenchmarkError::Skip)
|
||||
}
|
||||
|
||||
fn universal_alias() -> Result<Junction, BenchmarkError> {
|
||||
// The XCM executor of Kusama doesn't have a configured `UniversalAliases`
|
||||
Err(BenchmarkError::Skip)
|
||||
}
|
||||
|
||||
fn transact_origin_and_runtime_call() -> Result<(MultiLocation, RuntimeCall), BenchmarkError> {
|
||||
Ok((Statemine::get(), frame_system::Call::remark_with_event { remark: vec![] }.into()))
|
||||
}
|
||||
|
||||
fn subscribe_origin() -> Result<MultiLocation, BenchmarkError> {
|
||||
@@ -2045,10 +2056,15 @@ sp_api::impl_runtime_apis! {
|
||||
|
||||
fn claimable_asset() -> Result<(MultiLocation, MultiLocation, MultiAssets), BenchmarkError> {
|
||||
let origin = Statemine::get();
|
||||
let assets: MultiAssets = (Concrete(KsmLocation::get()), 1_000 * UNITS).into();
|
||||
let assets: MultiAssets = (Concrete(TokenLocation::get()), 1_000 * UNITS).into();
|
||||
let ticket = MultiLocation { parents: 0, interior: Here };
|
||||
Ok((origin, ticket, assets))
|
||||
}
|
||||
|
||||
fn unlockable_asset() -> Result<(MultiLocation, MultiLocation, MultiAsset), BenchmarkError> {
|
||||
// Kusama doesn't support asset locking
|
||||
Err(BenchmarkError::Skip)
|
||||
}
|
||||
}
|
||||
|
||||
let whitelist: Vec<TrackedStorageKey> = vec![
|
||||
|
||||
@@ -50,6 +50,7 @@ pub mod pallet_treasury;
|
||||
pub mod pallet_utility;
|
||||
pub mod pallet_vesting;
|
||||
pub mod pallet_whitelist;
|
||||
pub mod pallet_xcm;
|
||||
pub mod runtime_common_auctions;
|
||||
pub mod runtime_common_claims;
|
||||
pub mod runtime_common_crowdloan;
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
// Copyright 2017-2022 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/>.
|
||||
//! Autogenerated weights for `pallet_xcm`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2022-12-16, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024
|
||||
|
||||
// Executed Command:
|
||||
// /home/benchbot/cargo_target_dir/production/polkadot
|
||||
// benchmark
|
||||
// pallet
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
// --extrinsic=*
|
||||
// --execution=wasm
|
||||
// --wasm-execution=compiled
|
||||
// --heap-pages=4096
|
||||
// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/polkadot/.git/.artifacts/bench.json
|
||||
// --pallet=pallet_xcm
|
||||
// --chain=kusama-dev
|
||||
// --header=./file_header.txt
|
||||
// --output=./runtime/kusama/src/weights/
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use frame_support::{traits::Get, weights::Weight};
|
||||
use sp_std::marker::PhantomData;
|
||||
|
||||
/// Weight functions for `pallet_xcm`.
|
||||
pub struct WeightInfo<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
fn send() -> Weight {
|
||||
// Minimum execution time: 36_474 nanoseconds.
|
||||
Weight::from_ref_time(37_030_000)
|
||||
.saturating_add(T::DbWeight::get().reads(5))
|
||||
.saturating_add(T::DbWeight::get().writes(3))
|
||||
}
|
||||
fn teleport_assets() -> Weight {
|
||||
// Minimum execution time: 28_147 nanoseconds.
|
||||
Weight::from_ref_time(28_836_000)
|
||||
}
|
||||
fn reserve_transfer_assets() -> Weight {
|
||||
// Minimum execution time: 28_469 nanoseconds.
|
||||
Weight::from_ref_time(29_002_000)
|
||||
}
|
||||
fn execute() -> Weight {
|
||||
// Minimum execution time: 15_637 nanoseconds.
|
||||
Weight::from_ref_time(15_880_000)
|
||||
}
|
||||
// Storage: XcmPallet SupportedVersion (r:0 w:1)
|
||||
fn force_xcm_version() -> Weight {
|
||||
// Minimum execution time: 15_330 nanoseconds.
|
||||
Weight::from_ref_time(15_817_000)
|
||||
.saturating_add(T::DbWeight::get().writes(1))
|
||||
}
|
||||
// Storage: XcmPallet SafeXcmVersion (r:0 w:1)
|
||||
fn force_default_xcm_version() -> Weight {
|
||||
// Minimum execution time: 4_104 nanoseconds.
|
||||
Weight::from_ref_time(4_365_000)
|
||||
.saturating_add(T::DbWeight::get().writes(1))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifiers (r:1 w:1)
|
||||
// Storage: XcmPallet QueryCounter (r:1 w:1)
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
// Storage: XcmPallet Queries (r:0 w:1)
|
||||
fn force_subscribe_version_notify() -> Weight {
|
||||
// Minimum execution time: 42_177 nanoseconds.
|
||||
Weight::from_ref_time(42_657_000)
|
||||
.saturating_add(T::DbWeight::get().reads(7))
|
||||
.saturating_add(T::DbWeight::get().writes(6))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifiers (r:1 w:1)
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
// Storage: XcmPallet Queries (r:0 w:1)
|
||||
fn force_unsubscribe_version_notify() -> Weight {
|
||||
// Minimum execution time: 45_481 nanoseconds.
|
||||
Weight::from_ref_time(45_960_000)
|
||||
.saturating_add(T::DbWeight::get().reads(6))
|
||||
.saturating_add(T::DbWeight::get().writes(5))
|
||||
}
|
||||
// Storage: XcmPallet SupportedVersion (r:4 w:2)
|
||||
fn migrate_supported_version() -> Weight {
|
||||
// Minimum execution time: 14_899 nanoseconds.
|
||||
Weight::from_ref_time(15_452_000)
|
||||
.saturating_add(T::DbWeight::get().reads(4))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifiers (r:4 w:2)
|
||||
fn migrate_version_notifiers() -> Weight {
|
||||
// Minimum execution time: 14_759 nanoseconds.
|
||||
Weight::from_ref_time(15_176_000)
|
||||
.saturating_add(T::DbWeight::get().reads(4))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifyTargets (r:5 w:0)
|
||||
fn already_notified_target() -> Weight {
|
||||
// Minimum execution time: 17_022 nanoseconds.
|
||||
Weight::from_ref_time(17_468_000)
|
||||
.saturating_add(T::DbWeight::get().reads(5))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifyTargets (r:2 w:1)
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
fn notify_current_targets() -> Weight {
|
||||
// Minimum execution time: 37_810 nanoseconds.
|
||||
Weight::from_ref_time(38_198_000)
|
||||
.saturating_add(T::DbWeight::get().reads(7))
|
||||
.saturating_add(T::DbWeight::get().writes(4))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifyTargets (r:3 w:0)
|
||||
fn notify_target_migration_fail() -> Weight {
|
||||
// Minimum execution time: 7_440 nanoseconds.
|
||||
Weight::from_ref_time(7_659_000)
|
||||
.saturating_add(T::DbWeight::get().reads(3))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifyTargets (r:4 w:2)
|
||||
fn migrate_version_notify_targets() -> Weight {
|
||||
// Minimum execution time: 14_975 nanoseconds.
|
||||
Weight::from_ref_time(15_479_000)
|
||||
.saturating_add(T::DbWeight::get().reads(4))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifyTargets (r:4 w:2)
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
fn migrate_and_notify_old_targets() -> Weight {
|
||||
// Minimum execution time: 43_328 nanoseconds.
|
||||
Weight::from_ref_time(44_054_000)
|
||||
.saturating_add(T::DbWeight::get().reads(9))
|
||||
.saturating_add(T::DbWeight::get().writes(5))
|
||||
}
|
||||
}
|
||||
@@ -16,23 +16,25 @@
|
||||
//! Autogenerated weights for `runtime_parachains::ump`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2022-11-16, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
|
||||
//! DATE: 2023-01-16, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024
|
||||
|
||||
// Executed Command:
|
||||
// ./target/production/polkadot
|
||||
// /home/benchbot/cargo_target_dir/production/polkadot
|
||||
// benchmark
|
||||
// pallet
|
||||
// --chain=kusama-dev
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
// --pallet=runtime_parachains::ump
|
||||
// --extrinsic=*
|
||||
// --execution=wasm
|
||||
// --wasm-execution=compiled
|
||||
// --heap-pages=4096
|
||||
// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/polkadot/.git/.artifacts/bench.json
|
||||
// --pallet=runtime_parachains::ump
|
||||
// --chain=kusama-dev
|
||||
// --header=./file_header.txt
|
||||
// --output=./runtime/kusama/src/weights/runtime_parachains_ump.rs
|
||||
// --output=./runtime/kusama/src/weights/
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
@@ -46,26 +48,27 @@ pub struct WeightInfo<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> runtime_parachains::ump::WeightInfo for WeightInfo<T> {
|
||||
/// The range of component `s` is `[0, 51200]`.
|
||||
fn process_upward_message(s: u32, ) -> Weight {
|
||||
// Minimum execution time: 10_348 nanoseconds.
|
||||
Weight::from_ref_time(5_121_205 as u64)
|
||||
// Standard Error: 12
|
||||
.saturating_add(Weight::from_ref_time(1_934 as u64).saturating_mul(s as u64))
|
||||
// Minimum execution time: 10_393 nanoseconds.
|
||||
Weight::from_ref_time(2_845_995)
|
||||
// Standard Error: 21
|
||||
.saturating_add(Weight::from_ref_time(2_016).saturating_mul(s.into()))
|
||||
}
|
||||
// Storage: Ump NeedsDispatch (r:1 w:1)
|
||||
// Storage: Ump NextDispatchRoundStartWith (r:1 w:1)
|
||||
// Storage: Ump RelayDispatchQueues (r:0 w:1)
|
||||
// Storage: Ump RelayDispatchQueueSize (r:0 w:1)
|
||||
fn clean_ump_after_outgoing() -> Weight {
|
||||
// Minimum execution time: 9_800 nanoseconds.
|
||||
Weight::from_ref_time(10_025_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(2 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(4 as u64))
|
||||
// Minimum execution time: 9_686 nanoseconds.
|
||||
Weight::from_ref_time(9_920_000)
|
||||
.saturating_add(T::DbWeight::get().reads(2))
|
||||
.saturating_add(T::DbWeight::get().writes(4))
|
||||
}
|
||||
// Storage: Ump Overweight (r:1 w:1)
|
||||
// Storage: Ump CounterForOverweight (r:1 w:1)
|
||||
fn service_overweight() -> Weight {
|
||||
// Minimum execution time: 26_272 nanoseconds.
|
||||
Weight::from_ref_time(26_790_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(1 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as u64))
|
||||
// Minimum execution time: 28_502 nanoseconds.
|
||||
Weight::from_ref_time(28_900_000)
|
||||
.saturating_add(T::DbWeight::get().reads(2))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,7 @@ mod pallet_xcm_benchmarks_generic;
|
||||
use crate::Runtime;
|
||||
use frame_support::weights::Weight;
|
||||
use sp_std::prelude::*;
|
||||
use xcm::{
|
||||
latest::{prelude::*, Weight as XCMWeight},
|
||||
DoubleEncoded,
|
||||
};
|
||||
use xcm::{latest::prelude::*, DoubleEncoded};
|
||||
|
||||
use pallet_xcm_benchmarks_fungible::WeightInfo as XcmBalancesWeight;
|
||||
use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric;
|
||||
@@ -31,15 +28,15 @@ impl From<&MultiAsset> for AssetTypes {
|
||||
}
|
||||
|
||||
trait WeighMultiAssets {
|
||||
fn weigh_multi_assets(&self, balances_weight: Weight) -> XCMWeight;
|
||||
fn weigh_multi_assets(&self, balances_weight: Weight) -> Weight;
|
||||
}
|
||||
|
||||
// Kusama only knows about one asset, the balances pallet.
|
||||
const MAX_ASSETS: u32 = 1;
|
||||
|
||||
impl WeighMultiAssets for MultiAssetFilter {
|
||||
fn weigh_multi_assets(&self, balances_weight: Weight) -> XCMWeight {
|
||||
let weight = match self {
|
||||
fn weigh_multi_assets(&self, balances_weight: Weight) -> Weight {
|
||||
match self {
|
||||
Self::Definite(assets) => assets
|
||||
.inner()
|
||||
.into_iter()
|
||||
@@ -49,155 +46,213 @@ impl WeighMultiAssets for MultiAssetFilter {
|
||||
AssetTypes::Unknown => Weight::MAX,
|
||||
})
|
||||
.fold(Weight::zero(), |acc, x| acc.saturating_add(x)),
|
||||
Self::Wild(_) => balances_weight.saturating_mul(MAX_ASSETS as u64),
|
||||
};
|
||||
|
||||
weight.ref_time()
|
||||
Self::Wild(AllOf { .. } | AllOfCounted { .. }) => balances_weight,
|
||||
Self::Wild(AllCounted(count)) => balances_weight.saturating_mul(*count as u64),
|
||||
Self::Wild(All) => balances_weight.saturating_mul(MAX_ASSETS as u64),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WeighMultiAssets for MultiAssets {
|
||||
fn weigh_multi_assets(&self, balances_weight: Weight) -> XCMWeight {
|
||||
let weight = self
|
||||
.inner()
|
||||
fn weigh_multi_assets(&self, balances_weight: Weight) -> Weight {
|
||||
self.inner()
|
||||
.into_iter()
|
||||
.map(|m| <AssetTypes as From<&MultiAsset>>::from(m))
|
||||
.map(|t| match t {
|
||||
AssetTypes::Balances => balances_weight,
|
||||
AssetTypes::Unknown => Weight::MAX,
|
||||
})
|
||||
.fold(Weight::zero(), |acc, x| acc.saturating_add(x));
|
||||
|
||||
weight.ref_time()
|
||||
.fold(Weight::zero(), |acc, x| acc.saturating_add(x))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct KusamaXcmWeight<RuntimeCall>(core::marker::PhantomData<RuntimeCall>);
|
||||
impl<RuntimeCall> XcmWeightInfo<RuntimeCall> for KusamaXcmWeight<RuntimeCall> {
|
||||
fn withdraw_asset(assets: &MultiAssets) -> XCMWeight {
|
||||
fn withdraw_asset(assets: &MultiAssets) -> Weight {
|
||||
assets.weigh_multi_assets(XcmBalancesWeight::<Runtime>::withdraw_asset())
|
||||
}
|
||||
fn reserve_asset_deposited(assets: &MultiAssets) -> XCMWeight {
|
||||
fn reserve_asset_deposited(assets: &MultiAssets) -> Weight {
|
||||
assets.weigh_multi_assets(XcmBalancesWeight::<Runtime>::reserve_asset_deposited())
|
||||
}
|
||||
fn receive_teleported_asset(assets: &MultiAssets) -> XCMWeight {
|
||||
fn receive_teleported_asset(assets: &MultiAssets) -> Weight {
|
||||
assets.weigh_multi_assets(XcmBalancesWeight::<Runtime>::receive_teleported_asset())
|
||||
}
|
||||
fn query_response(_query_id: &u64, _response: &Response, _max_weight: &u64) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::query_response().ref_time()
|
||||
fn query_response(
|
||||
_query_id: &u64,
|
||||
_response: &Response,
|
||||
_max_weight: &Weight,
|
||||
_querier: &Option<MultiLocation>,
|
||||
) -> Weight {
|
||||
XcmGeneric::<Runtime>::query_response()
|
||||
}
|
||||
fn transfer_asset(assets: &MultiAssets, _dest: &MultiLocation) -> XCMWeight {
|
||||
fn transfer_asset(assets: &MultiAssets, _dest: &MultiLocation) -> Weight {
|
||||
assets.weigh_multi_assets(XcmBalancesWeight::<Runtime>::transfer_asset())
|
||||
}
|
||||
fn transfer_reserve_asset(
|
||||
assets: &MultiAssets,
|
||||
_dest: &MultiLocation,
|
||||
_xcm: &Xcm<()>,
|
||||
) -> XCMWeight {
|
||||
) -> Weight {
|
||||
assets.weigh_multi_assets(XcmBalancesWeight::<Runtime>::transfer_reserve_asset())
|
||||
}
|
||||
fn transact(
|
||||
_origin_type: &OriginKind,
|
||||
_require_weight_at_most: &u64,
|
||||
_origin_kind: &OriginKind,
|
||||
_require_weight_at_most: &Weight,
|
||||
_call: &DoubleEncoded<RuntimeCall>,
|
||||
) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::transact().ref_time()
|
||||
) -> Weight {
|
||||
XcmGeneric::<Runtime>::transact()
|
||||
}
|
||||
fn hrmp_new_channel_open_request(
|
||||
_sender: &u32,
|
||||
_max_message_size: &u32,
|
||||
_max_capacity: &u32,
|
||||
) -> XCMWeight {
|
||||
) -> Weight {
|
||||
// XCM Executor does not currently support HRMP channel operations
|
||||
Weight::MAX.ref_time()
|
||||
Weight::MAX
|
||||
}
|
||||
fn hrmp_channel_accepted(_recipient: &u32) -> XCMWeight {
|
||||
fn hrmp_channel_accepted(_recipient: &u32) -> Weight {
|
||||
// XCM Executor does not currently support HRMP channel operations
|
||||
Weight::MAX.ref_time()
|
||||
Weight::MAX
|
||||
}
|
||||
fn hrmp_channel_closing(_initiator: &u32, _sender: &u32, _recipient: &u32) -> XCMWeight {
|
||||
fn hrmp_channel_closing(_initiator: &u32, _sender: &u32, _recipient: &u32) -> Weight {
|
||||
// XCM Executor does not currently support HRMP channel operations
|
||||
Weight::MAX.ref_time()
|
||||
Weight::MAX
|
||||
}
|
||||
fn clear_origin() -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::clear_origin().ref_time()
|
||||
fn clear_origin() -> Weight {
|
||||
XcmGeneric::<Runtime>::clear_origin()
|
||||
}
|
||||
fn descend_origin(_who: &InteriorMultiLocation) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::descend_origin().ref_time()
|
||||
fn descend_origin(_who: &InteriorMultiLocation) -> Weight {
|
||||
XcmGeneric::<Runtime>::descend_origin()
|
||||
}
|
||||
fn report_error(
|
||||
_query_id: &QueryId,
|
||||
_dest: &MultiLocation,
|
||||
_max_response_weight: &u64,
|
||||
) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::report_error().ref_time()
|
||||
fn report_error(_query_response_info: &QueryResponseInfo) -> Weight {
|
||||
XcmGeneric::<Runtime>::report_error()
|
||||
}
|
||||
|
||||
fn deposit_asset(
|
||||
assets: &MultiAssetFilter,
|
||||
_max_assets: &u32, // TODO use max assets?
|
||||
_dest: &MultiLocation,
|
||||
) -> XCMWeight {
|
||||
fn deposit_asset(assets: &MultiAssetFilter, _dest: &MultiLocation) -> Weight {
|
||||
assets.weigh_multi_assets(XcmBalancesWeight::<Runtime>::deposit_asset())
|
||||
}
|
||||
fn deposit_reserve_asset(
|
||||
assets: &MultiAssetFilter,
|
||||
_max_assets: &u32, // TODO use max assets?
|
||||
_dest: &MultiLocation,
|
||||
_xcm: &Xcm<()>,
|
||||
) -> XCMWeight {
|
||||
) -> Weight {
|
||||
assets.weigh_multi_assets(XcmBalancesWeight::<Runtime>::deposit_reserve_asset())
|
||||
}
|
||||
fn exchange_asset(_give: &MultiAssetFilter, _receive: &MultiAssets) -> XCMWeight {
|
||||
Weight::MAX.ref_time() // todo fix
|
||||
fn exchange_asset(_give: &MultiAssetFilter, _receive: &MultiAssets, _maximal: &bool) -> Weight {
|
||||
// Kusama does not currently support exchange asset operations
|
||||
Weight::MAX
|
||||
}
|
||||
fn initiate_reserve_withdraw(
|
||||
assets: &MultiAssetFilter,
|
||||
_reserve: &MultiLocation,
|
||||
_xcm: &Xcm<()>,
|
||||
) -> XCMWeight {
|
||||
) -> Weight {
|
||||
assets.weigh_multi_assets(XcmGeneric::<Runtime>::initiate_reserve_withdraw())
|
||||
}
|
||||
fn initiate_teleport(
|
||||
assets: &MultiAssetFilter,
|
||||
_dest: &MultiLocation,
|
||||
_xcm: &Xcm<()>,
|
||||
) -> XCMWeight {
|
||||
) -> Weight {
|
||||
assets.weigh_multi_assets(XcmBalancesWeight::<Runtime>::initiate_teleport())
|
||||
}
|
||||
fn query_holding(
|
||||
_query_id: &u64,
|
||||
_dest: &MultiLocation,
|
||||
_assets: &MultiAssetFilter,
|
||||
_max_response_weight: &u64,
|
||||
) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::query_holding().ref_time()
|
||||
fn report_holding(_response_info: &QueryResponseInfo, _assets: &MultiAssetFilter) -> Weight {
|
||||
XcmGeneric::<Runtime>::report_holding()
|
||||
}
|
||||
fn buy_execution(_fees: &MultiAsset, _weight_limit: &WeightLimit) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::buy_execution().ref_time()
|
||||
fn buy_execution(_fees: &MultiAsset, _weight_limit: &WeightLimit) -> Weight {
|
||||
XcmGeneric::<Runtime>::buy_execution()
|
||||
}
|
||||
fn refund_surplus() -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::refund_surplus().ref_time()
|
||||
fn refund_surplus() -> Weight {
|
||||
XcmGeneric::<Runtime>::refund_surplus()
|
||||
}
|
||||
fn set_error_handler(_xcm: &Xcm<RuntimeCall>) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::set_error_handler().ref_time()
|
||||
fn set_error_handler(_xcm: &Xcm<RuntimeCall>) -> Weight {
|
||||
XcmGeneric::<Runtime>::set_error_handler()
|
||||
}
|
||||
fn set_appendix(_xcm: &Xcm<RuntimeCall>) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::set_appendix().ref_time()
|
||||
fn set_appendix(_xcm: &Xcm<RuntimeCall>) -> Weight {
|
||||
XcmGeneric::<Runtime>::set_appendix()
|
||||
}
|
||||
fn clear_error() -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::clear_error().ref_time()
|
||||
fn clear_error() -> Weight {
|
||||
XcmGeneric::<Runtime>::clear_error()
|
||||
}
|
||||
fn claim_asset(_assets: &MultiAssets, _ticket: &MultiLocation) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::claim_asset().ref_time()
|
||||
fn claim_asset(_assets: &MultiAssets, _ticket: &MultiLocation) -> Weight {
|
||||
XcmGeneric::<Runtime>::claim_asset()
|
||||
}
|
||||
fn trap(_code: &u64) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::trap().ref_time()
|
||||
fn trap(_code: &u64) -> Weight {
|
||||
XcmGeneric::<Runtime>::trap()
|
||||
}
|
||||
fn subscribe_version(_query_id: &QueryId, _max_response_weight: &u64) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::subscribe_version().ref_time()
|
||||
fn subscribe_version(_query_id: &QueryId, _max_response_weight: &Weight) -> Weight {
|
||||
XcmGeneric::<Runtime>::subscribe_version()
|
||||
}
|
||||
fn unsubscribe_version() -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::unsubscribe_version().ref_time()
|
||||
fn unsubscribe_version() -> Weight {
|
||||
XcmGeneric::<Runtime>::unsubscribe_version()
|
||||
}
|
||||
fn burn_asset(assets: &MultiAssets) -> Weight {
|
||||
assets.weigh_multi_assets(XcmGeneric::<Runtime>::burn_asset())
|
||||
}
|
||||
fn expect_asset(assets: &MultiAssets) -> Weight {
|
||||
assets.weigh_multi_assets(XcmGeneric::<Runtime>::expect_asset())
|
||||
}
|
||||
fn expect_origin(_origin: &Option<MultiLocation>) -> Weight {
|
||||
XcmGeneric::<Runtime>::expect_origin()
|
||||
}
|
||||
fn expect_error(_error: &Option<(u32, XcmError)>) -> Weight {
|
||||
XcmGeneric::<Runtime>::expect_error()
|
||||
}
|
||||
fn query_pallet(_module_name: &Vec<u8>, _response_info: &QueryResponseInfo) -> Weight {
|
||||
XcmGeneric::<Runtime>::query_pallet()
|
||||
}
|
||||
fn expect_pallet(
|
||||
_index: &u32,
|
||||
_name: &Vec<u8>,
|
||||
_module_name: &Vec<u8>,
|
||||
_crate_major: &u32,
|
||||
_min_crate_minor: &u32,
|
||||
) -> Weight {
|
||||
XcmGeneric::<Runtime>::expect_pallet()
|
||||
}
|
||||
fn report_transact_status(_response_info: &QueryResponseInfo) -> Weight {
|
||||
XcmGeneric::<Runtime>::report_transact_status()
|
||||
}
|
||||
fn clear_transact_status() -> Weight {
|
||||
XcmGeneric::<Runtime>::clear_transact_status()
|
||||
}
|
||||
fn universal_origin(_: &Junction) -> Weight {
|
||||
// Kusama does not currently support universal origin operations
|
||||
Weight::MAX
|
||||
}
|
||||
fn export_message(_: &NetworkId, _: &Junctions, _: &Xcm<()>) -> Weight {
|
||||
Weight::MAX // todo fix
|
||||
}
|
||||
fn lock_asset(_: &MultiAsset, _: &MultiLocation) -> Weight {
|
||||
// Kusama does not currently support asset locking operations
|
||||
Weight::MAX
|
||||
}
|
||||
fn unlock_asset(_: &MultiAsset, _: &MultiLocation) -> Weight {
|
||||
// Kusama does not currently support asset locking operations
|
||||
Weight::MAX
|
||||
}
|
||||
fn note_unlockable(_: &MultiAsset, _: &MultiLocation) -> Weight {
|
||||
// Kusama does not currently support asset locking operations
|
||||
Weight::MAX
|
||||
}
|
||||
fn request_unlock(_: &MultiAsset, _: &MultiLocation) -> Weight {
|
||||
// Kusama does not currently support asset locking operations
|
||||
Weight::MAX
|
||||
}
|
||||
fn set_fees_mode(_: &bool) -> Weight {
|
||||
XcmGeneric::<Runtime>::set_fees_mode()
|
||||
}
|
||||
fn set_topic(_topic: &[u8; 32]) -> Weight {
|
||||
XcmGeneric::<Runtime>::set_topic()
|
||||
}
|
||||
fn clear_topic() -> Weight {
|
||||
XcmGeneric::<Runtime>::clear_topic()
|
||||
}
|
||||
fn alias_origin(_: &MultiLocation) -> Weight {
|
||||
// XCM Executor does not currently support alias origin operations
|
||||
Weight::MAX
|
||||
}
|
||||
fn unpaid_execution(_: &WeightLimit, _: &Option<MultiLocation>) -> Weight {
|
||||
XcmGeneric::<Runtime>::unpaid_execution()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,12 +17,13 @@
|
||||
//! Autogenerated weights for `pallet_xcm_benchmarks::generic`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2022-03-08, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! DATE: 2022-04-18, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024
|
||||
|
||||
// Executed Command:
|
||||
// target/production/polkadot
|
||||
// benchmark
|
||||
// pallet
|
||||
// --chain=kusama-dev
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
@@ -48,89 +49,135 @@ impl<T: frame_system::Config> WeightInfo<T> {
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
pub(crate) fn query_holding() -> Weight {
|
||||
Weight::from_ref_time(21_822_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(6 as u64))
|
||||
pub(crate) fn report_holding() -> Weight {
|
||||
Weight::from_ref_time(25_878_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(5 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as u64))
|
||||
}
|
||||
pub(crate) fn buy_execution() -> Weight {
|
||||
Weight::from_ref_time(3_109_000 as u64)
|
||||
Weight::from_ref_time(3_697_000 as u64)
|
||||
}
|
||||
// Storage: XcmPallet Queries (r:1 w:0)
|
||||
pub(crate) fn query_response() -> Weight {
|
||||
Weight::from_ref_time(12_087_000 as u64)
|
||||
Weight::from_ref_time(13_458_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(1 as u64))
|
||||
}
|
||||
pub(crate) fn transact() -> Weight {
|
||||
Weight::from_ref_time(12_398_000 as u64)
|
||||
Weight::from_ref_time(13_597_000 as u64)
|
||||
}
|
||||
pub(crate) fn refund_surplus() -> Weight {
|
||||
Weight::from_ref_time(3_247_000 as u64)
|
||||
Weight::from_ref_time(3_839_000 as u64)
|
||||
}
|
||||
pub(crate) fn set_error_handler() -> Weight {
|
||||
Weight::from_ref_time(3_086_000 as u64)
|
||||
Weight::from_ref_time(3_657_000 as u64)
|
||||
}
|
||||
pub(crate) fn set_appendix() -> Weight {
|
||||
Weight::from_ref_time(3_112_000 as u64)
|
||||
Weight::from_ref_time(3_757_000 as u64)
|
||||
}
|
||||
pub(crate) fn clear_error() -> Weight {
|
||||
Weight::from_ref_time(3_118_000 as u64)
|
||||
Weight::from_ref_time(3_651_000 as u64)
|
||||
}
|
||||
pub(crate) fn descend_origin() -> Weight {
|
||||
Weight::from_ref_time(4_054_000 as u64)
|
||||
Weight::from_ref_time(4_589_000 as u64)
|
||||
}
|
||||
pub(crate) fn clear_origin() -> Weight {
|
||||
Weight::from_ref_time(3_111_000 as u64)
|
||||
Weight::from_ref_time(3_661_000 as u64)
|
||||
}
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
pub(crate) fn report_error() -> Weight {
|
||||
Weight::from_ref_time(18_425_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(6 as u64))
|
||||
Weight::from_ref_time(21_351_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(5 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as u64))
|
||||
}
|
||||
// Storage: XcmPallet AssetTraps (r:1 w:1)
|
||||
pub(crate) fn claim_asset() -> Weight {
|
||||
Weight::from_ref_time(7_144_000 as u64)
|
||||
Weight::from_ref_time(7_674_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(1 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as u64))
|
||||
}
|
||||
pub(crate) fn trap() -> Weight {
|
||||
Weight::from_ref_time(3_060_000 as u64)
|
||||
Weight::from_ref_time(3_606_000 as u64)
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifyTargets (r:1 w:1)
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
pub(crate) fn subscribe_version() -> Weight {
|
||||
Weight::from_ref_time(21_642_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(7 as u64))
|
||||
Weight::from_ref_time(30_453_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(6 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(4 as u64))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifyTargets (r:0 w:1)
|
||||
pub(crate) fn unsubscribe_version() -> Weight {
|
||||
Weight::from_ref_time(4_873_000 as u64)
|
||||
Weight::from_ref_time(5_543_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().writes(1 as u64))
|
||||
}
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
pub(crate) fn initiate_reserve_withdraw() -> Weight {
|
||||
Weight::from_ref_time(22_809_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(6 as u64))
|
||||
Weight::from_ref_time(25_464_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(5 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as u64))
|
||||
}
|
||||
pub(crate) fn burn_asset() -> Weight {
|
||||
Weight::from_ref_time(5_194_000 as u64)
|
||||
}
|
||||
pub(crate) fn expect_asset() -> Weight {
|
||||
Weight::from_ref_time(3_698_000 as u64)
|
||||
}
|
||||
pub(crate) fn expect_origin() -> Weight {
|
||||
Weight::from_ref_time(3_786_000 as u64)
|
||||
}
|
||||
pub(crate) fn expect_error() -> Weight {
|
||||
Weight::from_ref_time(3_645_000 as u64)
|
||||
}
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
pub(crate) fn query_pallet() -> Weight {
|
||||
Weight::from_ref_time(22_993_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(5 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as u64))
|
||||
}
|
||||
pub(crate) fn expect_pallet() -> Weight {
|
||||
Weight::from_ref_time(4_043_000 as u64)
|
||||
}
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
pub(crate) fn report_transact_status() -> Weight {
|
||||
Weight::from_ref_time(21_668_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(5 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as u64))
|
||||
}
|
||||
pub(crate) fn clear_transact_status() -> Weight {
|
||||
Weight::from_ref_time(3_673_000 as u64)
|
||||
}
|
||||
pub(crate) fn set_topic() -> Weight {
|
||||
Weight::from_ref_time(3_661_000 as u64)
|
||||
}
|
||||
pub(crate) fn clear_topic() -> Weight {
|
||||
Weight::from_ref_time(3_647_000 as u64)
|
||||
}
|
||||
pub(crate) fn set_fees_mode() -> Weight {
|
||||
Weight::from_ref_time(3_599_000 as u64)
|
||||
}
|
||||
pub(crate) fn unpaid_execution() -> Weight {
|
||||
Weight::from_ref_time(3_111_000 as u64)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,33 +17,44 @@
|
||||
//! XCM configurations for the Kusama runtime.
|
||||
|
||||
use super::{
|
||||
parachains_origin, AccountId, Balances, CouncilCollective, Fellows, ParaId, Runtime,
|
||||
RuntimeCall, RuntimeEvent, RuntimeOrigin, StakingAdmin, WeightToFee, XcmPallet,
|
||||
parachains_origin, AccountId, AllPalletsWithSystem, Balances, CouncilCollective, Fellows,
|
||||
ParaId, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, StakingAdmin, WeightToFee,
|
||||
XcmPallet,
|
||||
};
|
||||
use frame_support::{
|
||||
match_types, parameter_types,
|
||||
traits::{Contains, Everything, Nothing},
|
||||
weights::Weight,
|
||||
};
|
||||
use frame_support::{match_types, parameter_types, traits::Everything};
|
||||
use runtime_common::{xcm_sender, ToAuthor};
|
||||
use sp_core::ConstU32;
|
||||
use xcm::latest::prelude::*;
|
||||
use xcm_builder::{
|
||||
AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom,
|
||||
AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, BackingToPlurality,
|
||||
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
|
||||
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, BackingToPlurality,
|
||||
ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser,
|
||||
CurrencyAdapter as XcmCurrencyAdapter, FixedWeightBounds, IsChildSystemParachain, IsConcrete,
|
||||
LocationInverter, OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32,
|
||||
MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32,
|
||||
SovereignSignedViaLocation, TakeWeightCredit, UsingComponents, WeightInfoBounds,
|
||||
WithComputedOrigin,
|
||||
};
|
||||
use xcm_executor::traits::WithOriginFilter;
|
||||
|
||||
parameter_types! {
|
||||
/// The location of the KSM token, from the context of this chain. Since this token is native to this
|
||||
/// chain, we make it synonymous with it and thus it is the `Here` location, which means "equivalent to
|
||||
/// the context".
|
||||
pub const KsmLocation: MultiLocation = Here.into();
|
||||
pub const TokenLocation: MultiLocation = Here.into_location();
|
||||
/// The Kusama network ID. This is named.
|
||||
pub const KusamaNetwork: NetworkId = NetworkId::Kusama;
|
||||
/// Our XCM location ancestry - i.e. what, if anything, `Parent` means evaluated in our context. Since
|
||||
/// Kusama is a top-level relay-chain, there is no ancestry.
|
||||
pub const Ancestry: MultiLocation = Here.into();
|
||||
pub const ThisNetwork: NetworkId = Kusama;
|
||||
/// Our XCM location ancestry - i.e. our location within the Consensus Universe.
|
||||
///
|
||||
/// Since Kusama is a top-level relay-chain with its own consensus, it's just our network ID.
|
||||
pub UniversalLocation: InteriorMultiLocation = ThisNetwork::get().into();
|
||||
/// The check account, which holds any native assets that have been teleported out and not back in (yet).
|
||||
pub CheckAccount: AccountId = XcmPallet::check_account();
|
||||
/// The check account that is allowed to mint assets locally.
|
||||
pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local);
|
||||
}
|
||||
|
||||
/// The canonical means of converting a `MultiLocation` into an `AccountId`, used when we want to determine
|
||||
@@ -52,41 +63,41 @@ pub type SovereignAccountOf = (
|
||||
// We can convert a child parachain using the standard `AccountId` conversion.
|
||||
ChildParachainConvertsVia<ParaId, AccountId>,
|
||||
// We can directly alias an `AccountId32` into a local account.
|
||||
AccountId32Aliases<KusamaNetwork, AccountId>,
|
||||
AccountId32Aliases<ThisNetwork, AccountId>,
|
||||
);
|
||||
|
||||
/// Our asset transactor. This is what allows us to interest with the runtime facilities from the point of
|
||||
/// view of XCM-only concepts like `MultiLocation` and `MultiAsset`.
|
||||
///
|
||||
/// Ours is only aware of the Balances pallet, which is mapped to `KsmLocation`.
|
||||
/// Ours is only aware of the Balances pallet, which is mapped to `TokenLocation`.
|
||||
pub type LocalAssetTransactor = XcmCurrencyAdapter<
|
||||
// Use this currency:
|
||||
Balances,
|
||||
// Use this currency when it is a fungible asset matching the given location or name:
|
||||
IsConcrete<KsmLocation>,
|
||||
IsConcrete<TokenLocation>,
|
||||
// We can convert the MultiLocations with our converter above:
|
||||
SovereignAccountOf,
|
||||
// Our chain's account ID type (we can't get away without mentioning it explicitly):
|
||||
AccountId,
|
||||
// We track our teleports in/out to keep total issuance correct.
|
||||
CheckAccount,
|
||||
LocalCheckAccount,
|
||||
>;
|
||||
|
||||
/// The means that we convert an the XCM message origin location into a local dispatch origin.
|
||||
/// The means that we convert the XCM message origin location into a local dispatch origin.
|
||||
type LocalOriginConverter = (
|
||||
// A `Signed` origin of the sovereign account that the original location controls.
|
||||
SovereignSignedViaLocation<SovereignAccountOf, RuntimeOrigin>,
|
||||
// A child parachain, natively expressed, has the `Parachain` origin.
|
||||
ChildParachainAsNative<parachains_origin::Origin, RuntimeOrigin>,
|
||||
// The AccountId32 location type can be expressed natively as a `Signed` origin.
|
||||
SignedAccountId32AsNative<KusamaNetwork, RuntimeOrigin>,
|
||||
SignedAccountId32AsNative<ThisNetwork, RuntimeOrigin>,
|
||||
// A system child parachain, expressed as a Superuser, converts to the `Root` origin.
|
||||
ChildSystemParachainAsSuperuser<ParaId, RuntimeOrigin>,
|
||||
);
|
||||
|
||||
parameter_types! {
|
||||
/// The amount of weight an XCM operation takes. This is a safe overestimate.
|
||||
pub const BaseXcmWeight: u64 = 1_000_000_000;
|
||||
pub const BaseXcmWeight: Weight = Weight::from_parts(1_000_000_000, 64 * 1024);
|
||||
/// Maximum number of instructions in a single XCM fragment. A sanity check against weight
|
||||
/// calculations getting too crazy.
|
||||
pub const MaxInstructions: u32 = 100;
|
||||
@@ -96,18 +107,19 @@ parameter_types! {
|
||||
/// individual routers.
|
||||
pub type XcmRouter = (
|
||||
// Only one router so far - use DMP to communicate with child parachains.
|
||||
xcm_sender::ChildParachainRouter<Runtime, XcmPallet>,
|
||||
xcm_sender::ChildParachainRouter<Runtime, XcmPallet, ()>,
|
||||
);
|
||||
|
||||
parameter_types! {
|
||||
pub const Kusama: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(KsmLocation::get()) });
|
||||
pub const Statemine: MultiLocation = Parachain(1000).into();
|
||||
pub const Encointer: MultiLocation = Parachain(1001).into();
|
||||
pub const KusamaForStatemine: (MultiAssetFilter, MultiLocation) = (Kusama::get(), Statemine::get());
|
||||
pub const KusamaForEncointer: (MultiAssetFilter, MultiLocation) = (Kusama::get(), Encointer::get());
|
||||
pub const Ksm: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) });
|
||||
pub const Statemine: MultiLocation = Parachain(1000).into_location();
|
||||
pub const Encointer: MultiLocation = Parachain(1001).into_location();
|
||||
pub const KsmForStatemine: (MultiAssetFilter, MultiLocation) = (Ksm::get(), Statemine::get());
|
||||
pub const KsmForEncointer: (MultiAssetFilter, MultiLocation) = (Ksm::get(), Encointer::get());
|
||||
pub const MaxAssetsIntoHolding: u32 = 64;
|
||||
}
|
||||
pub type TrustedTeleporters =
|
||||
(xcm_builder::Case<KusamaForStatemine>, xcm_builder::Case<KusamaForEncointer>);
|
||||
(xcm_builder::Case<KsmForStatemine>, xcm_builder::Case<KsmForEncointer>);
|
||||
|
||||
match_types! {
|
||||
pub type OnlyParachains: impl Contains<MultiLocation> = {
|
||||
@@ -119,16 +131,209 @@ match_types! {
|
||||
pub type Barrier = (
|
||||
// Weight that is paid for may be consumed.
|
||||
TakeWeightCredit,
|
||||
// If the message is one that immediately attemps to pay for execution, then allow it.
|
||||
AllowTopLevelPaidExecutionFrom<Everything>,
|
||||
// Messages coming from system parachains need not pay for execution.
|
||||
AllowUnpaidExecutionFrom<IsChildSystemParachain<ParaId>>,
|
||||
// Expected responses are OK.
|
||||
AllowKnownQueryResponses<XcmPallet>,
|
||||
// Subscriptions for version tracking are OK.
|
||||
AllowSubscriptionsFrom<OnlyParachains>,
|
||||
WithComputedOrigin<
|
||||
(
|
||||
// If the message is one that immediately attempts to pay for execution, then allow it.
|
||||
AllowTopLevelPaidExecutionFrom<Everything>,
|
||||
// Messages coming from system parachains need not pay for execution.
|
||||
AllowExplicitUnpaidExecutionFrom<IsChildSystemParachain<ParaId>>,
|
||||
// Subscriptions for version tracking are OK.
|
||||
AllowSubscriptionsFrom<OnlyParachains>,
|
||||
),
|
||||
UniversalLocation,
|
||||
ConstU32<8>,
|
||||
>,
|
||||
);
|
||||
|
||||
/// A call filter for the XCM Transact instruction. This is a temporary measure until we properly
|
||||
/// account for proof size weights.
|
||||
///
|
||||
/// Calls that are allowed through this filter must:
|
||||
/// 1. Have a fixed weight;
|
||||
/// 2. Cannot lead to another call being made;
|
||||
/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call parameters.
|
||||
pub struct SafeCallFilter;
|
||||
impl Contains<RuntimeCall> for SafeCallFilter {
|
||||
fn contains(call: &RuntimeCall) -> bool {
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
{
|
||||
if matches!(call, RuntimeCall::System(frame_system::Call::remark_with_event { .. })) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
match call {
|
||||
RuntimeCall::System(
|
||||
frame_system::Call::kill_prefix { .. } | frame_system::Call::set_heap_pages { .. },
|
||||
) |
|
||||
RuntimeCall::Babe(..) |
|
||||
RuntimeCall::Timestamp(..) |
|
||||
RuntimeCall::Indices(..) |
|
||||
RuntimeCall::Balances(..) |
|
||||
RuntimeCall::Staking(
|
||||
pallet_staking::Call::bond { .. } |
|
||||
pallet_staking::Call::bond_extra { .. } |
|
||||
pallet_staking::Call::unbond { .. } |
|
||||
pallet_staking::Call::withdraw_unbonded { .. } |
|
||||
pallet_staking::Call::validate { .. } |
|
||||
pallet_staking::Call::nominate { .. } |
|
||||
pallet_staking::Call::chill { .. } |
|
||||
pallet_staking::Call::set_payee { .. } |
|
||||
pallet_staking::Call::set_controller { .. } |
|
||||
pallet_staking::Call::set_validator_count { .. } |
|
||||
pallet_staking::Call::increase_validator_count { .. } |
|
||||
pallet_staking::Call::scale_validator_count { .. } |
|
||||
pallet_staking::Call::force_no_eras { .. } |
|
||||
pallet_staking::Call::force_new_era { .. } |
|
||||
pallet_staking::Call::set_invulnerables { .. } |
|
||||
pallet_staking::Call::force_unstake { .. } |
|
||||
pallet_staking::Call::force_new_era_always { .. } |
|
||||
pallet_staking::Call::payout_stakers { .. } |
|
||||
pallet_staking::Call::rebond { .. } |
|
||||
pallet_staking::Call::reap_stash { .. } |
|
||||
pallet_staking::Call::set_staking_configs { .. } |
|
||||
pallet_staking::Call::chill_other { .. } |
|
||||
pallet_staking::Call::force_apply_min_commission { .. },
|
||||
) |
|
||||
RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) |
|
||||
RuntimeCall::Grandpa(..) |
|
||||
RuntimeCall::ImOnline(..) |
|
||||
RuntimeCall::Democracy(
|
||||
pallet_democracy::Call::second { .. } |
|
||||
pallet_democracy::Call::vote { .. } |
|
||||
pallet_democracy::Call::emergency_cancel { .. } |
|
||||
pallet_democracy::Call::fast_track { .. } |
|
||||
pallet_democracy::Call::veto_external { .. } |
|
||||
pallet_democracy::Call::cancel_referendum { .. } |
|
||||
pallet_democracy::Call::delegate { .. } |
|
||||
pallet_democracy::Call::undelegate { .. } |
|
||||
pallet_democracy::Call::clear_public_proposals { .. } |
|
||||
pallet_democracy::Call::unlock { .. } |
|
||||
pallet_democracy::Call::remove_vote { .. } |
|
||||
pallet_democracy::Call::remove_other_vote { .. } |
|
||||
pallet_democracy::Call::blacklist { .. } |
|
||||
pallet_democracy::Call::cancel_proposal { .. },
|
||||
) |
|
||||
RuntimeCall::Council(
|
||||
pallet_collective::Call::vote { .. } |
|
||||
pallet_collective::Call::close_old_weight { .. } |
|
||||
pallet_collective::Call::disapprove_proposal { .. } |
|
||||
pallet_collective::Call::close { .. },
|
||||
) |
|
||||
RuntimeCall::TechnicalCommittee(
|
||||
pallet_collective::Call::vote { .. } |
|
||||
pallet_collective::Call::close_old_weight { .. } |
|
||||
pallet_collective::Call::disapprove_proposal { .. } |
|
||||
pallet_collective::Call::close { .. },
|
||||
) |
|
||||
RuntimeCall::PhragmenElection(
|
||||
pallet_elections_phragmen::Call::remove_voter { .. } |
|
||||
pallet_elections_phragmen::Call::submit_candidacy { .. } |
|
||||
pallet_elections_phragmen::Call::renounce_candidacy { .. } |
|
||||
pallet_elections_phragmen::Call::remove_member { .. } |
|
||||
pallet_elections_phragmen::Call::clean_defunct_voters { .. },
|
||||
) |
|
||||
RuntimeCall::TechnicalMembership(
|
||||
pallet_membership::Call::add_member { .. } |
|
||||
pallet_membership::Call::remove_member { .. } |
|
||||
pallet_membership::Call::swap_member { .. } |
|
||||
pallet_membership::Call::change_key { .. } |
|
||||
pallet_membership::Call::set_prime { .. } |
|
||||
pallet_membership::Call::clear_prime { .. },
|
||||
) |
|
||||
RuntimeCall::Treasury(..) |
|
||||
RuntimeCall::ConvictionVoting(..) |
|
||||
RuntimeCall::Referenda(
|
||||
pallet_referenda::Call::place_decision_deposit { .. } |
|
||||
pallet_referenda::Call::refund_decision_deposit { .. } |
|
||||
pallet_referenda::Call::cancel { .. } |
|
||||
pallet_referenda::Call::kill { .. } |
|
||||
pallet_referenda::Call::nudge_referendum { .. } |
|
||||
pallet_referenda::Call::one_fewer_deciding { .. },
|
||||
) |
|
||||
RuntimeCall::FellowshipCollective(..) |
|
||||
RuntimeCall::FellowshipReferenda(
|
||||
pallet_referenda::Call::place_decision_deposit { .. } |
|
||||
pallet_referenda::Call::refund_decision_deposit { .. } |
|
||||
pallet_referenda::Call::cancel { .. } |
|
||||
pallet_referenda::Call::kill { .. } |
|
||||
pallet_referenda::Call::nudge_referendum { .. } |
|
||||
pallet_referenda::Call::one_fewer_deciding { .. },
|
||||
) |
|
||||
RuntimeCall::Claims(
|
||||
super::claims::Call::claim { .. } |
|
||||
super::claims::Call::mint_claim { .. } |
|
||||
super::claims::Call::move_claim { .. },
|
||||
) |
|
||||
RuntimeCall::Utility(pallet_utility::Call::as_derivative { .. }) |
|
||||
RuntimeCall::Identity(
|
||||
pallet_identity::Call::add_registrar { .. } |
|
||||
pallet_identity::Call::set_identity { .. } |
|
||||
pallet_identity::Call::clear_identity { .. } |
|
||||
pallet_identity::Call::request_judgement { .. } |
|
||||
pallet_identity::Call::cancel_request { .. } |
|
||||
pallet_identity::Call::set_fee { .. } |
|
||||
pallet_identity::Call::set_account_id { .. } |
|
||||
pallet_identity::Call::set_fields { .. } |
|
||||
pallet_identity::Call::provide_judgement { .. } |
|
||||
pallet_identity::Call::kill_identity { .. } |
|
||||
pallet_identity::Call::add_sub { .. } |
|
||||
pallet_identity::Call::rename_sub { .. } |
|
||||
pallet_identity::Call::remove_sub { .. } |
|
||||
pallet_identity::Call::quit_sub { .. },
|
||||
) |
|
||||
RuntimeCall::Society(
|
||||
pallet_society::Call::bid { .. } |
|
||||
pallet_society::Call::unbid { .. } |
|
||||
pallet_society::Call::vouch { .. } |
|
||||
pallet_society::Call::unvouch { .. } |
|
||||
pallet_society::Call::vote { .. } |
|
||||
pallet_society::Call::defender_vote { .. } |
|
||||
pallet_society::Call::payout { .. } |
|
||||
pallet_society::Call::unfound { .. } |
|
||||
pallet_society::Call::judge_suspended_member { .. } |
|
||||
pallet_society::Call::judge_suspended_candidate { .. } |
|
||||
pallet_society::Call::set_max_members { .. },
|
||||
) |
|
||||
RuntimeCall::Recovery(..) |
|
||||
RuntimeCall::Vesting(..) |
|
||||
RuntimeCall::Bounties(
|
||||
pallet_bounties::Call::propose_bounty { .. } |
|
||||
pallet_bounties::Call::approve_bounty { .. } |
|
||||
pallet_bounties::Call::propose_curator { .. } |
|
||||
pallet_bounties::Call::unassign_curator { .. } |
|
||||
pallet_bounties::Call::accept_curator { .. } |
|
||||
pallet_bounties::Call::award_bounty { .. } |
|
||||
pallet_bounties::Call::claim_bounty { .. } |
|
||||
pallet_bounties::Call::close_bounty { .. },
|
||||
) |
|
||||
RuntimeCall::ChildBounties(..) |
|
||||
RuntimeCall::ElectionProviderMultiPhase(..) |
|
||||
RuntimeCall::VoterList(..) |
|
||||
RuntimeCall::NominationPools(
|
||||
pallet_nomination_pools::Call::join { .. } |
|
||||
pallet_nomination_pools::Call::bond_extra { .. } |
|
||||
pallet_nomination_pools::Call::claim_payout { .. } |
|
||||
pallet_nomination_pools::Call::unbond { .. } |
|
||||
pallet_nomination_pools::Call::pool_withdraw_unbonded { .. } |
|
||||
pallet_nomination_pools::Call::withdraw_unbonded { .. } |
|
||||
pallet_nomination_pools::Call::create { .. } |
|
||||
pallet_nomination_pools::Call::create_with_pool_id { .. } |
|
||||
pallet_nomination_pools::Call::set_state { .. } |
|
||||
pallet_nomination_pools::Call::set_configs { .. } |
|
||||
pallet_nomination_pools::Call::update_roles { .. } |
|
||||
pallet_nomination_pools::Call::chill { .. },
|
||||
) |
|
||||
RuntimeCall::XcmPallet(pallet_xcm::Call::limited_reserve_transfer_assets {
|
||||
..
|
||||
}) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct XcmConfig;
|
||||
impl xcm_executor::Config for XcmConfig {
|
||||
type RuntimeCall = RuntimeCall;
|
||||
@@ -137,7 +342,7 @@ impl xcm_executor::Config for XcmConfig {
|
||||
type OriginConverter = LocalOriginConverter;
|
||||
type IsReserve = ();
|
||||
type IsTeleporter = TrustedTeleporters;
|
||||
type LocationInverter = LocationInverter<Ancestry>;
|
||||
type UniversalLocation = UniversalLocation;
|
||||
type Barrier = Barrier;
|
||||
type Weigher = WeightInfoBounds<
|
||||
crate::weights::xcm::KusamaXcmWeight<RuntimeCall>,
|
||||
@@ -145,11 +350,22 @@ impl xcm_executor::Config for XcmConfig {
|
||||
MaxInstructions,
|
||||
>;
|
||||
// The weight trader piggybacks on the existing transaction-fee conversion logic.
|
||||
type Trader = UsingComponents<WeightToFee, KsmLocation, AccountId, Balances, ToAuthor<Runtime>>;
|
||||
type Trader =
|
||||
UsingComponents<WeightToFee, TokenLocation, AccountId, Balances, ToAuthor<Runtime>>;
|
||||
type ResponseHandler = XcmPallet;
|
||||
type AssetTrap = XcmPallet;
|
||||
type AssetLocker = ();
|
||||
type AssetExchanger = ();
|
||||
type AssetClaims = XcmPallet;
|
||||
type SubscriptionService = XcmPallet;
|
||||
type PalletInstancesInfo = AllPalletsWithSystem;
|
||||
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
|
||||
type FeeManager = ();
|
||||
// No bridges yet...
|
||||
type MessageExporter = ();
|
||||
type UniversalAliases = Nothing;
|
||||
type CallDispatcher = WithOriginFilter<SafeCallFilter>;
|
||||
type SafeCallFilter = SafeCallFilter;
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
@@ -160,6 +376,11 @@ parameter_types! {
|
||||
pub const FellowsBodyId: BodyId = BodyId::Technical;
|
||||
}
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
parameter_types! {
|
||||
pub ReachableDest: Option<MultiLocation> = Some(Parachain(1000).into());
|
||||
}
|
||||
|
||||
/// Type to convert the council origin to a Plurality `MultiLocation` value.
|
||||
pub type CouncilToPlurality = BackingToPlurality<
|
||||
RuntimeOrigin,
|
||||
@@ -174,7 +395,7 @@ pub type LocalOriginToLocation = (
|
||||
// `Unit` body.
|
||||
CouncilToPlurality,
|
||||
// And a usual Signed origin to be used in XCM as a corresponding AccountId32
|
||||
SignedToAccountId32<RuntimeOrigin, AccountId, KusamaNetwork>,
|
||||
SignedToAccountId32<RuntimeOrigin, AccountId, ThisNetwork>,
|
||||
);
|
||||
|
||||
/// Type to convert the `StakingAdmin` origin to a Plurality `MultiLocation` value.
|
||||
@@ -214,9 +435,17 @@ impl pallet_xcm::Config for Runtime {
|
||||
// transfer.
|
||||
type XcmReserveTransferFilter = Everything;
|
||||
type Weigher = FixedWeightBounds<BaseXcmWeight, RuntimeCall, MaxInstructions>;
|
||||
type LocationInverter = LocationInverter<Ancestry>;
|
||||
type UniversalLocation = UniversalLocation;
|
||||
type RuntimeOrigin = RuntimeOrigin;
|
||||
type RuntimeCall = RuntimeCall;
|
||||
const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
|
||||
type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
|
||||
type Currency = Balances;
|
||||
type CurrencyMatcher = ();
|
||||
type TrustedLockers = ();
|
||||
type SovereignAccountOf = SovereignAccountOf;
|
||||
type MaxLockers = ConstU32<8>;
|
||||
type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type ReachableDest = ReachableDest;
|
||||
}
|
||||
|
||||
@@ -227,7 +227,6 @@ ump_max_individual_weight : pre.ump_max_individual_weight,
|
||||
pvf_checking_enabled : pre.pvf_checking_enabled,
|
||||
pvf_voting_ttl : pre.pvf_voting_ttl,
|
||||
minimum_validation_upgrade_delay : pre.minimum_validation_upgrade_delay,
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -318,7 +318,7 @@ fn setting_pending_config_members() {
|
||||
max_upward_queue_count: 1337,
|
||||
max_upward_queue_size: 228,
|
||||
max_downward_message_size: 2048,
|
||||
ump_service_total_weight: Weight::from_ref_time(20000),
|
||||
ump_service_total_weight: Weight::from_parts(20000, 20000),
|
||||
max_upward_message_size: 448,
|
||||
max_upward_message_num_per_candidate: 5,
|
||||
hrmp_sender_deposit: 22,
|
||||
@@ -331,7 +331,7 @@ fn setting_pending_config_members() {
|
||||
hrmp_max_parachain_outbound_channels: 10,
|
||||
hrmp_max_parathread_outbound_channels: 20,
|
||||
hrmp_max_message_num_per_candidate: 20,
|
||||
ump_max_individual_weight: Weight::from_ref_time(909),
|
||||
ump_max_individual_weight: Weight::from_parts(909, 909),
|
||||
pvf_checking_enabled: true,
|
||||
pvf_voting_ttl: 3,
|
||||
minimum_validation_upgrade_delay: 20,
|
||||
|
||||
@@ -973,7 +973,7 @@ impl<T: Config> Pallet<T> {
|
||||
|
||||
/// Handle a set of dispute statements corresponding to a single candidate.
|
||||
///
|
||||
/// Fails if the dispute data is invalid. Returns a boolean indicating whether the
|
||||
/// Fails if the dispute data is invalid. Returns a Boolean indicating whether the
|
||||
/// dispute is fresh.
|
||||
fn process_checked_dispute_data(
|
||||
set: CheckedDisputeStatementSet,
|
||||
|
||||
@@ -29,6 +29,8 @@ pub use pallet::*;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub const MAX_MESSAGE_QUEUE_SIZE: usize = 1024;
|
||||
|
||||
/// An error sending a downward message.
|
||||
#[cfg_attr(test, derive(Debug))]
|
||||
pub enum QueueDownwardMessageError {
|
||||
@@ -137,6 +139,28 @@ impl<T: Config> Pallet<T> {
|
||||
<Self as Store>::DownwardMessageQueueHeads::remove(outgoing_para);
|
||||
}
|
||||
|
||||
/// Determine whether enqueuing a downward message to a specific recipient para would result
|
||||
/// in an error. If this returns `Ok(())` the caller can be certain that a call to
|
||||
/// `queue_downward_message` with the same parameters will be successful.
|
||||
pub fn can_queue_downward_message(
|
||||
config: &HostConfiguration<T::BlockNumber>,
|
||||
para: &ParaId,
|
||||
msg: &DownwardMessage,
|
||||
) -> Result<(), QueueDownwardMessageError> {
|
||||
let serialized_len = msg.len() as u32;
|
||||
if serialized_len > config.max_downward_message_size {
|
||||
return Err(QueueDownwardMessageError::ExceedsMaxMessageSize)
|
||||
}
|
||||
|
||||
if <Self as Store>::DownwardMessageQueues::decode_len(para).unwrap_or(0) >
|
||||
MAX_MESSAGE_QUEUE_SIZE
|
||||
{
|
||||
return Err(QueueDownwardMessageError::ExceedsMaxMessageSize)
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Enqueue a downward message to a specific recipient para.
|
||||
///
|
||||
/// When encoded, the message should not exceed the `config.max_downward_message_size`.
|
||||
@@ -155,6 +179,12 @@ impl<T: Config> Pallet<T> {
|
||||
return Err(QueueDownwardMessageError::ExceedsMaxMessageSize)
|
||||
}
|
||||
|
||||
if <Self as Store>::DownwardMessageQueues::decode_len(para).unwrap_or(0) >
|
||||
MAX_MESSAGE_QUEUE_SIZE
|
||||
{
|
||||
return Err(QueueDownwardMessageError::ExceedsMaxMessageSize)
|
||||
}
|
||||
|
||||
let inbound =
|
||||
InboundDownwardMessage { msg, sent_at: <frame_system::Pallet<T>>::block_number() };
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ parameter_types! {
|
||||
pub const BlockHashCount: u32 = 250;
|
||||
pub BlockWeights: frame_system::limits::BlockWeights =
|
||||
frame_system::limits::BlockWeights::simple_max(
|
||||
Weight::from_ref_time(4 * 1024 * 1024).set_proof_size(u64::MAX),
|
||||
Weight::from_parts(4 * 1024 * 1024, u64::MAX),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -394,7 +394,7 @@ impl UmpSink for TestUmpSink {
|
||||
max_weight: Weight,
|
||||
) -> Result<Weight, (MessageId, Weight)> {
|
||||
let weight = match u32::decode(&mut &actual_msg[..]) {
|
||||
Ok(w) => Weight::from_ref_time(w as u64),
|
||||
Ok(w) => Weight::from_parts(w as u64, w as u64),
|
||||
Err(_) => return Ok(Weight::zero()), // same as the real `UmpSink`
|
||||
};
|
||||
if weight.any_gt(max_weight) {
|
||||
|
||||
@@ -159,7 +159,7 @@ pub struct ReplacementTimes<N> {
|
||||
#[cfg_attr(test, derive(Debug, Clone, PartialEq))]
|
||||
pub struct ParaPastCodeMeta<N> {
|
||||
/// Block numbers where the code was expected to be replaced and where the code
|
||||
/// was actually replaced, respectively. The first is used to do accurate lookups
|
||||
/// was actually replaced, respectively. The first is used to do accurate look-ups
|
||||
/// of historic code in historic contexts, whereas the second is used to do
|
||||
/// pruning on an accurate timeframe. These can be used as indices
|
||||
/// into the `PastCodeHash` map along with the `ParaId` to fetch the code itself.
|
||||
@@ -520,7 +520,7 @@ impl WeightInfo for TestWeightInfo {
|
||||
}
|
||||
fn include_pvf_check_statement() -> Weight {
|
||||
// This special value is to distinguish from the finalizing variants above in tests.
|
||||
Weight::MAX - Weight::from_ref_time(1)
|
||||
Weight::MAX - Weight::from_parts(1, 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,9 +31,12 @@ pub use pallet::*;
|
||||
/// This is used for benchmarking sanely bounding relevant storate items. It is expected from the `configurations`
|
||||
/// pallet to check these values before setting.
|
||||
pub const MAX_UPWARD_MESSAGE_SIZE_BOUND: u32 = 50 * 1024;
|
||||
/// Maximum amount of overweight messages that can exist in the queue at any given time.
|
||||
pub const MAX_OVERWEIGHT_MESSAGES: u32 = 1000;
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
mod benchmarking;
|
||||
pub mod migration;
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests;
|
||||
@@ -133,13 +136,11 @@ impl<XcmExecutor: xcm::latest::ExecuteXcm<C::RuntimeCall>, C: Config> UmpSink
|
||||
},
|
||||
Ok((Ok(xcm_message), weight_used)) => {
|
||||
let xcm_junction = Junction::Parachain(origin.into());
|
||||
let outcome =
|
||||
XcmExecutor::execute_xcm(xcm_junction, xcm_message, max_weight.ref_time());
|
||||
let outcome = XcmExecutor::execute_xcm(xcm_junction, xcm_message, id, max_weight);
|
||||
match outcome {
|
||||
Outcome::Error(XcmError::WeightLimitReached(required)) =>
|
||||
Err((id, Weight::from_ref_time(required))),
|
||||
Outcome::Error(XcmError::WeightLimitReached(required)) => Err((id, required)),
|
||||
outcome => {
|
||||
let outcome_weight = Weight::from_ref_time(outcome.weight_used());
|
||||
let outcome_weight = outcome.weight_used();
|
||||
Pallet::<C>::deposit_event(Event::ExecutedUpward(id, outcome));
|
||||
Ok(weight_used.saturating_add(outcome_weight))
|
||||
},
|
||||
@@ -215,6 +216,7 @@ pub mod pallet {
|
||||
#[pallet::pallet]
|
||||
#[pallet::generate_store(pub(super) trait Store)]
|
||||
#[pallet::without_storage_info]
|
||||
#[pallet::storage_version(migration::STORAGE_VERSION)]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::config]
|
||||
@@ -328,7 +330,7 @@ pub mod pallet {
|
||||
/// These messages stay there until manually dispatched.
|
||||
#[pallet::storage]
|
||||
pub type Overweight<T: Config> =
|
||||
StorageMap<_, Twox64Concat, OverweightIndex, (ParaId, Vec<u8>), OptionQuery>;
|
||||
CountedStorageMap<_, Twox64Concat, OverweightIndex, (ParaId, Vec<u8>), OptionQuery>;
|
||||
|
||||
/// The number of overweight messages ever recorded in `Overweight` (and thus the lowest free
|
||||
/// index).
|
||||
@@ -508,6 +510,8 @@ impl<T: Config> Pallet<T> {
|
||||
|
||||
/// Devote some time into dispatching pending upward messages.
|
||||
pub(crate) fn process_pending_upward_messages() -> Weight {
|
||||
const MAX_MESSAGES_PER_BLOCK: u8 = 10;
|
||||
let mut messages_processed = 0;
|
||||
let mut weight_used = Weight::zero();
|
||||
|
||||
let config = <configuration::Pallet<T>>::config();
|
||||
@@ -515,7 +519,12 @@ impl<T: Config> Pallet<T> {
|
||||
let mut queue_cache = QueueCache::new();
|
||||
|
||||
while let Some(dispatchee) = cursor.peek() {
|
||||
if weight_used.any_gte(config.ump_service_total_weight) {
|
||||
if weight_used.any_gte(config.ump_service_total_weight) ||
|
||||
messages_processed >= MAX_MESSAGES_PER_BLOCK
|
||||
{
|
||||
// Temporarily allow for processing of a max of 10 messages per block, until we
|
||||
// properly account for proof size weights.
|
||||
//
|
||||
// Then check whether we've reached or overshoot the
|
||||
// preferred weight for the dispatching stage.
|
||||
//
|
||||
@@ -537,13 +546,16 @@ impl<T: Config> Pallet<T> {
|
||||
// our remaining weight limit, then consume it.
|
||||
let maybe_next = queue_cache.peek_front::<T>(dispatchee);
|
||||
if let Some(upward_message) = maybe_next {
|
||||
messages_processed += 1;
|
||||
match T::UmpSink::process_upward_message(dispatchee, upward_message, max_weight) {
|
||||
Ok(used) => {
|
||||
weight_used += used;
|
||||
let _ = queue_cache.consume_front::<T>(dispatchee);
|
||||
},
|
||||
Err((id, required)) => {
|
||||
if required.any_gt(config.ump_max_individual_weight) {
|
||||
let is_under_limit = Overweight::<T>::count() < MAX_OVERWEIGHT_MESSAGES;
|
||||
weight_used.saturating_accrue(T::DbWeight::get().reads(1));
|
||||
if required.any_gt(config.ump_max_individual_weight) && is_under_limit {
|
||||
// overweight - add to overweight queue and continue with message
|
||||
// execution consuming the message.
|
||||
let upward_message = queue_cache.consume_front::<T>(dispatchee).expect(
|
||||
|
||||
@@ -42,8 +42,8 @@ fn queue_upward_msg<T: Config>(
|
||||
fn create_message_min_size<T: Config>(size: u32) -> Vec<u8> {
|
||||
// Create a message with an empty remark call to determine the encoding overhead
|
||||
let msg_size_empty_transact = VersionedXcm::<T>::from(Xcm::<T>(vec![Transact {
|
||||
origin_type: OriginKind::SovereignAccount,
|
||||
require_weight_at_most: Weight::MAX.ref_time(),
|
||||
origin_kind: OriginKind::SovereignAccount,
|
||||
require_weight_at_most: Weight::MAX,
|
||||
call: frame_system::Call::<T>::remark_with_event { remark: vec![] }.encode().into(),
|
||||
}]))
|
||||
.encode()
|
||||
@@ -54,8 +54,8 @@ fn create_message_min_size<T: Config>(size: u32) -> Vec<u8> {
|
||||
let mut remark = Vec::new();
|
||||
remark.resize(size, 0u8);
|
||||
let msg = VersionedXcm::<T>::from(Xcm::<T>(vec![Transact {
|
||||
origin_type: OriginKind::SovereignAccount,
|
||||
require_weight_at_most: Weight::MAX.ref_time(),
|
||||
origin_kind: OriginKind::SovereignAccount,
|
||||
require_weight_at_most: Weight::MAX,
|
||||
call: frame_system::Call::<T>::remark_with_event { remark }.encode().into(),
|
||||
}]))
|
||||
.encode();
|
||||
@@ -65,12 +65,11 @@ fn create_message_min_size<T: Config>(size: u32) -> Vec<u8> {
|
||||
}
|
||||
|
||||
fn create_message_overweight<T: Config>() -> Vec<u8> {
|
||||
let max_block_weight = T::BlockWeights::get().max_block;
|
||||
// We use a `set_code` Call because it
|
||||
let call = frame_system::Call::<T>::set_code { code: vec![] };
|
||||
VersionedXcm::<T>::from(Xcm::<T>(vec![Transact {
|
||||
origin_type: OriginKind::Superuser,
|
||||
require_weight_at_most: max_block_weight.ref_time(),
|
||||
origin_kind: OriginKind::Superuser,
|
||||
require_weight_at_most: Weight::MAX / 2,
|
||||
call: call.encode().into(),
|
||||
}]))
|
||||
.encode()
|
||||
@@ -107,7 +106,6 @@ frame_benchmarking::benchmarks! {
|
||||
|
||||
service_overweight {
|
||||
let host_conf = configuration::ActiveConfig::<T>::get();
|
||||
let weight = host_conf.ump_max_individual_weight + host_conf.ump_max_individual_weight + Weight::from_ref_time(1000000);
|
||||
let para = ParaId::from(1978);
|
||||
// The message's weight does not really matter here, as we add service_overweight's
|
||||
// max_weight parameter to the extrinsic's weight in the weight calculation.
|
||||
@@ -117,7 +115,7 @@ frame_benchmarking::benchmarks! {
|
||||
let msg = create_message_overweight::<T>();
|
||||
|
||||
// This just makes sure that 0 is not a valid index and we can use it later on.
|
||||
let _ = Ump::<T>::service_overweight(RawOrigin::Root.into(), 0, Weight::from_ref_time(1000).set_proof_size(u64::MAX));
|
||||
let _ = Ump::<T>::service_overweight(RawOrigin::Root.into(), 0, Weight::from_parts(1000, 1000));
|
||||
// Start with the block number 1. This is needed because should an event be
|
||||
// emitted during the genesis block they will be implicitly wiped.
|
||||
frame_system::Pallet::<T>::set_block_number(1u32.into());
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright 2022 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/>.
|
||||
|
||||
use crate::ump::{Config, Overweight, Pallet};
|
||||
use frame_support::{
|
||||
pallet_prelude::*,
|
||||
traits::{OnRuntimeUpgrade, StorageVersion},
|
||||
weights::Weight,
|
||||
};
|
||||
|
||||
pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||
|
||||
pub mod v1 {
|
||||
use super::*;
|
||||
|
||||
pub struct MigrateToV1<T>(sp_std::marker::PhantomData<T>);
|
||||
impl<T: Config> OnRuntimeUpgrade for MigrateToV1<T> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
if StorageVersion::get::<Pallet<T>>() == 0 {
|
||||
let mut weight = T::DbWeight::get().reads(1);
|
||||
|
||||
let overweight_messages = Overweight::<T>::initialize_counter() as u64;
|
||||
log::info!("Initialized Overweight to {}", overweight_messages);
|
||||
|
||||
weight.saturating_accrue(T::DbWeight::get().reads_writes(overweight_messages, 1));
|
||||
|
||||
StorageVersion::new(1).put::<Pallet<T>>();
|
||||
|
||||
weight.saturating_add(T::DbWeight::get().writes(1))
|
||||
} else {
|
||||
log::warn!("skipping v1, should be removed");
|
||||
T::DbWeight::get().reads(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,12 +34,12 @@ pub(super) struct GenesisConfigBuilder {
|
||||
impl Default for GenesisConfigBuilder {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
max_upward_message_size: 16,
|
||||
max_upward_message_size: 32,
|
||||
max_upward_message_num_per_candidate: 2,
|
||||
max_upward_queue_count: 4,
|
||||
max_upward_queue_size: 64,
|
||||
ump_service_total_weight: Weight::from_ref_time(1000).set_proof_size(1000),
|
||||
ump_max_individual_weight: Weight::from_ref_time(100).set_proof_size(100),
|
||||
ump_service_total_weight: Weight::from_parts(1000, 1000),
|
||||
ump_max_individual_weight: Weight::from_parts(100, 100),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -156,7 +156,7 @@ fn dispatch_resume_after_exceeding_dispatch_stage_weight() {
|
||||
|
||||
new_test_ext(
|
||||
GenesisConfigBuilder {
|
||||
ump_service_total_weight: Weight::from_ref_time(500).set_proof_size(500),
|
||||
ump_service_total_weight: Weight::from_parts(500, 500),
|
||||
..Default::default()
|
||||
}
|
||||
.build(),
|
||||
@@ -203,8 +203,8 @@ fn dispatch_keeps_message_after_weight_exhausted() {
|
||||
|
||||
new_test_ext(
|
||||
GenesisConfigBuilder {
|
||||
ump_service_total_weight: Weight::from_ref_time(500).set_proof_size(500),
|
||||
ump_max_individual_weight: Weight::from_ref_time(300).set_proof_size(300),
|
||||
ump_service_total_weight: Weight::from_parts(500, 500),
|
||||
ump_max_individual_weight: Weight::from_parts(300, 300),
|
||||
..Default::default()
|
||||
}
|
||||
.build(),
|
||||
@@ -243,7 +243,7 @@ fn dispatch_correctly_handle_remove_of_latest() {
|
||||
|
||||
new_test_ext(
|
||||
GenesisConfigBuilder {
|
||||
ump_service_total_weight: Weight::from_ref_time(900).set_proof_size(900),
|
||||
ump_service_total_weight: Weight::from_parts(900, 900),
|
||||
..Default::default()
|
||||
}
|
||||
.build(),
|
||||
@@ -296,7 +296,7 @@ fn service_overweight_unknown() {
|
||||
// the next test.
|
||||
new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| {
|
||||
assert_noop!(
|
||||
Ump::service_overweight(RuntimeOrigin::root(), 0, Weight::from_ref_time(1000)),
|
||||
Ump::service_overweight(RuntimeOrigin::root(), 0, Weight::from_parts(1000, 1000)),
|
||||
Error::<Test>::UnknownMessageIndex
|
||||
);
|
||||
});
|
||||
@@ -312,8 +312,8 @@ fn overweight_queue_works() {
|
||||
|
||||
new_test_ext(
|
||||
GenesisConfigBuilder {
|
||||
ump_service_total_weight: Weight::from_ref_time(900).set_proof_size(900),
|
||||
ump_max_individual_weight: Weight::from_ref_time(300).set_proof_size(300),
|
||||
ump_service_total_weight: Weight::from_parts(900, 900),
|
||||
ump_max_individual_weight: Weight::from_parts(300, 300),
|
||||
..Default::default()
|
||||
}
|
||||
.build(),
|
||||
@@ -338,7 +338,7 @@ fn overweight_queue_works() {
|
||||
para_a,
|
||||
upward_message_id(&a_msg_3[..]),
|
||||
0,
|
||||
Weight::from_ref_time(500),
|
||||
Weight::from_parts(500, 500),
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
@@ -346,18 +346,18 @@ fn overweight_queue_works() {
|
||||
// Now verify that if we wanted to service this overweight message with less than enough
|
||||
// weight it will fail.
|
||||
assert_noop!(
|
||||
Ump::service_overweight(RuntimeOrigin::root(), 0, Weight::from_ref_time(499)),
|
||||
Ump::service_overweight(RuntimeOrigin::root(), 0, Weight::from_parts(499, 499)),
|
||||
Error::<Test>::WeightOverLimit
|
||||
);
|
||||
|
||||
// ... and if we try to service it with just enough weight it will succeed as well.
|
||||
assert_ok!(Ump::service_overweight(RuntimeOrigin::root(), 0, Weight::from_ref_time(500)));
|
||||
assert_last_event(Event::OverweightServiced(0, Weight::from_ref_time(500)).into());
|
||||
assert_ok!(Ump::service_overweight(RuntimeOrigin::root(), 0, Weight::from_parts(500, 500)));
|
||||
assert_last_event(Event::OverweightServiced(0, Weight::from_parts(500, 500)).into());
|
||||
|
||||
// ... and if we try to service a message with index that doesn't exist it will error
|
||||
// out.
|
||||
assert_noop!(
|
||||
Ump::service_overweight(RuntimeOrigin::root(), 1, Weight::from_ref_time(1000)),
|
||||
Ump::service_overweight(RuntimeOrigin::root(), 1, Weight::from_parts(1000, 1000)),
|
||||
Error::<Test>::UnknownMessageIndex
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1303,7 +1303,7 @@ impl parachains_ump::Config for Runtime {
|
||||
crate::parachains_ump::XcmSink<xcm_executor::XcmExecutor<xcm_config::XcmConfig>, Runtime>;
|
||||
type FirstMessageFactorPercent = FirstMessageFactorPercent;
|
||||
type ExecuteOverweightOrigin = EnsureRoot<AccountId>;
|
||||
type WeightInfo = parachains_ump::TestWeightInfo;
|
||||
type WeightInfo = weights::runtime_parachains_ump::WeightInfo<Self>;
|
||||
}
|
||||
|
||||
impl parachains_dmp::Config for Runtime {}
|
||||
@@ -1609,6 +1609,9 @@ pub type Migrations = (
|
||||
pallet_staking::migrations::v13::MigrateToV13<Runtime>,
|
||||
parachains_disputes::migration::v1::MigrateToV1<Runtime>,
|
||||
parachains_configuration::migration::v4::MigrateToV4<Runtime>,
|
||||
// "Use 2D weights in XCM v3" <https://github.com/paritytech/polkadot/pull/6134>
|
||||
pallet_xcm::migration::v1::MigrateToV1<Runtime>,
|
||||
parachains_ump::migration::v1::MigrateToV1<Runtime>,
|
||||
);
|
||||
|
||||
/// Unchecked extrinsic type as expected by this runtime.
|
||||
@@ -1680,6 +1683,8 @@ mod benches {
|
||||
[pallet_treasury, Treasury]
|
||||
[pallet_utility, Utility]
|
||||
[pallet_vesting, Vesting]
|
||||
// XCM
|
||||
[pallet_xcm, XcmPallet]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ pub mod pallet_tips;
|
||||
pub mod pallet_treasury;
|
||||
pub mod pallet_utility;
|
||||
pub mod pallet_vesting;
|
||||
pub mod pallet_xcm;
|
||||
pub mod runtime_common_auctions;
|
||||
pub mod runtime_common_claims;
|
||||
pub mod runtime_common_crowdloan;
|
||||
@@ -54,3 +55,4 @@ pub mod runtime_parachains_hrmp;
|
||||
pub mod runtime_parachains_initializer;
|
||||
pub mod runtime_parachains_paras;
|
||||
pub mod runtime_parachains_paras_inherent;
|
||||
pub mod runtime_parachains_ump;
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
// Copyright 2017-2022 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/>.
|
||||
//! Autogenerated weights for `pallet_xcm`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2022-12-16, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024
|
||||
|
||||
// Executed Command:
|
||||
// /home/benchbot/cargo_target_dir/production/polkadot
|
||||
// benchmark
|
||||
// pallet
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
// --extrinsic=*
|
||||
// --execution=wasm
|
||||
// --wasm-execution=compiled
|
||||
// --heap-pages=4096
|
||||
// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/polkadot/.git/.artifacts/bench.json
|
||||
// --pallet=pallet_xcm
|
||||
// --chain=polkadot-dev
|
||||
// --header=./file_header.txt
|
||||
// --output=./runtime/polkadot/src/weights/
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use frame_support::{traits::Get, weights::Weight};
|
||||
use sp_std::marker::PhantomData;
|
||||
|
||||
/// Weight functions for `pallet_xcm`.
|
||||
pub struct WeightInfo<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
fn send() -> Weight {
|
||||
// Minimum execution time: 35_717 nanoseconds.
|
||||
Weight::from_ref_time(36_278_000)
|
||||
.saturating_add(T::DbWeight::get().reads(6))
|
||||
.saturating_add(T::DbWeight::get().writes(3))
|
||||
}
|
||||
fn teleport_assets() -> Weight {
|
||||
// Minimum execution time: 28_865 nanoseconds.
|
||||
Weight::from_ref_time(29_336_000)
|
||||
}
|
||||
fn reserve_transfer_assets() -> Weight {
|
||||
// Minimum execution time: 27_531 nanoseconds.
|
||||
Weight::from_ref_time(28_248_000)
|
||||
}
|
||||
// Storage: Benchmark Override (r:0 w:0)
|
||||
fn execute() -> Weight {
|
||||
// Minimum execution time: 18_446_744_073_709_551 nanoseconds.
|
||||
Weight::from_ref_time(18_446_744_073_709_551_000)
|
||||
}
|
||||
// Storage: XcmPallet SupportedVersion (r:0 w:1)
|
||||
fn force_xcm_version() -> Weight {
|
||||
// Minimum execution time: 15_205 nanoseconds.
|
||||
Weight::from_ref_time(15_526_000)
|
||||
.saturating_add(T::DbWeight::get().writes(1))
|
||||
}
|
||||
// Storage: XcmPallet SafeXcmVersion (r:0 w:1)
|
||||
fn force_default_xcm_version() -> Weight {
|
||||
// Minimum execution time: 4_336 nanoseconds.
|
||||
Weight::from_ref_time(4_518_000)
|
||||
.saturating_add(T::DbWeight::get().writes(1))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifiers (r:1 w:1)
|
||||
// Storage: XcmPallet QueryCounter (r:1 w:1)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
// Storage: XcmPallet Queries (r:0 w:1)
|
||||
fn force_subscribe_version_notify() -> Weight {
|
||||
// Minimum execution time: 41_446 nanoseconds.
|
||||
Weight::from_ref_time(42_152_000)
|
||||
.saturating_add(T::DbWeight::get().reads(8))
|
||||
.saturating_add(T::DbWeight::get().writes(6))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifiers (r:1 w:1)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
// Storage: XcmPallet Queries (r:0 w:1)
|
||||
fn force_unsubscribe_version_notify() -> Weight {
|
||||
// Minimum execution time: 44_944 nanoseconds.
|
||||
Weight::from_ref_time(45_519_000)
|
||||
.saturating_add(T::DbWeight::get().reads(7))
|
||||
.saturating_add(T::DbWeight::get().writes(5))
|
||||
}
|
||||
// Storage: XcmPallet SupportedVersion (r:4 w:2)
|
||||
fn migrate_supported_version() -> Weight {
|
||||
// Minimum execution time: 15_254 nanoseconds.
|
||||
Weight::from_ref_time(15_491_000)
|
||||
.saturating_add(T::DbWeight::get().reads(4))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifiers (r:4 w:2)
|
||||
fn migrate_version_notifiers() -> Weight {
|
||||
// Minimum execution time: 15_083 nanoseconds.
|
||||
Weight::from_ref_time(15_298_000)
|
||||
.saturating_add(T::DbWeight::get().reads(4))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifyTargets (r:5 w:0)
|
||||
fn already_notified_target() -> Weight {
|
||||
// Minimum execution time: 17_889 nanoseconds.
|
||||
Weight::from_ref_time(18_144_000)
|
||||
.saturating_add(T::DbWeight::get().reads(5))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifyTargets (r:2 w:1)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
fn notify_current_targets() -> Weight {
|
||||
// Minimum execution time: 37_255 nanoseconds.
|
||||
Weight::from_ref_time(37_893_000)
|
||||
.saturating_add(T::DbWeight::get().reads(8))
|
||||
.saturating_add(T::DbWeight::get().writes(4))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifyTargets (r:3 w:0)
|
||||
fn notify_target_migration_fail() -> Weight {
|
||||
// Minimum execution time: 7_884 nanoseconds.
|
||||
Weight::from_ref_time(8_111_000)
|
||||
.saturating_add(T::DbWeight::get().reads(3))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifyTargets (r:4 w:2)
|
||||
fn migrate_version_notify_targets() -> Weight {
|
||||
// Minimum execution time: 15_853 nanoseconds.
|
||||
Weight::from_ref_time(16_220_000)
|
||||
.saturating_add(T::DbWeight::get().reads(4))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifyTargets (r:4 w:2)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
fn migrate_and_notify_old_targets() -> Weight {
|
||||
// Minimum execution time: 43_836 nanoseconds.
|
||||
Weight::from_ref_time(44_836_000)
|
||||
.saturating_add(T::DbWeight::get().reads(10))
|
||||
.saturating_add(T::DbWeight::get().writes(5))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
// Copyright 2017-2022 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/>.
|
||||
//! Autogenerated weights for `runtime_parachains::ump`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2023-01-16, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024
|
||||
|
||||
// Executed Command:
|
||||
// /home/benchbot/cargo_target_dir/production/polkadot
|
||||
// benchmark
|
||||
// pallet
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
// --extrinsic=*
|
||||
// --execution=wasm
|
||||
// --wasm-execution=compiled
|
||||
// --heap-pages=4096
|
||||
// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/polkadot/.git/.artifacts/bench.json
|
||||
// --pallet=runtime_parachains::ump
|
||||
// --chain=polkadot-dev
|
||||
// --header=./file_header.txt
|
||||
// --output=./runtime/polkadot/src/weights/
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use frame_support::{traits::Get, weights::Weight};
|
||||
use sp_std::marker::PhantomData;
|
||||
|
||||
/// Weight functions for `runtime_parachains::ump`.
|
||||
pub struct WeightInfo<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> runtime_parachains::ump::WeightInfo for WeightInfo<T> {
|
||||
/// The range of component `s` is `[0, 51200]`.
|
||||
fn process_upward_message(s: u32, ) -> Weight {
|
||||
// Minimum execution time: 10_291 nanoseconds.
|
||||
Weight::from_ref_time(4_272_368)
|
||||
// Standard Error: 12
|
||||
.saturating_add(Weight::from_ref_time(1_872).saturating_mul(s.into()))
|
||||
}
|
||||
// Storage: Ump NeedsDispatch (r:1 w:1)
|
||||
// Storage: Ump NextDispatchRoundStartWith (r:1 w:1)
|
||||
// Storage: Ump RelayDispatchQueues (r:0 w:1)
|
||||
// Storage: Ump RelayDispatchQueueSize (r:0 w:1)
|
||||
fn clean_ump_after_outgoing() -> Weight {
|
||||
// Minimum execution time: 9_837 nanoseconds.
|
||||
Weight::from_ref_time(9_951_000)
|
||||
.saturating_add(T::DbWeight::get().reads(2))
|
||||
.saturating_add(T::DbWeight::get().writes(4))
|
||||
}
|
||||
// Storage: Ump Overweight (r:1 w:1)
|
||||
// Storage: Ump CounterForOverweight (r:1 w:1)
|
||||
fn service_overweight() -> Weight {
|
||||
// Minimum execution time: 29_540 nanoseconds.
|
||||
Weight::from_ref_time(29_889_000)
|
||||
.saturating_add(T::DbWeight::get().reads(2))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
}
|
||||
}
|
||||
@@ -17,35 +17,39 @@
|
||||
//! XCM configuration for Polkadot.
|
||||
|
||||
use super::{
|
||||
parachains_origin, AccountId, Balances, CouncilCollective, ParaId, Runtime, RuntimeCall,
|
||||
RuntimeEvent, RuntimeOrigin, WeightToFee, XcmPallet,
|
||||
parachains_origin, AccountId, AllPalletsWithSystem, Balances, CouncilCollective, ParaId,
|
||||
Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmPallet,
|
||||
};
|
||||
use frame_support::{
|
||||
match_types, parameter_types,
|
||||
traits::{Everything, Nothing},
|
||||
traits::{Contains, Everything, Nothing},
|
||||
weights::Weight,
|
||||
};
|
||||
use runtime_common::{xcm_sender, ToAuthor};
|
||||
use sp_core::ConstU32;
|
||||
use xcm::latest::prelude::*;
|
||||
use xcm_builder::{
|
||||
AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom,
|
||||
AllowTopLevelPaidExecutionFrom, BackingToPlurality, ChildParachainAsNative,
|
||||
ChildParachainConvertsVia, CurrencyAdapter as XcmCurrencyAdapter, FixedWeightBounds,
|
||||
IsConcrete, LocationInverter, SignedAccountId32AsNative, SignedToAccountId32,
|
||||
SovereignSignedViaLocation, TakeWeightCredit, UsingComponents,
|
||||
IsConcrete, MintLocation, SignedAccountId32AsNative, SignedToAccountId32,
|
||||
SovereignSignedViaLocation, TakeWeightCredit, UsingComponents, WithComputedOrigin,
|
||||
};
|
||||
use xcm_executor::traits::WithOriginFilter;
|
||||
|
||||
parameter_types! {
|
||||
/// The location of the DOT token, from the context of this chain. Since this token is native to this
|
||||
/// chain, we make it synonymous with it and thus it is the `Here` location, which means "equivalent to
|
||||
/// the context".
|
||||
pub const DotLocation: MultiLocation = Here.into();
|
||||
pub const TokenLocation: MultiLocation = Here.into_location();
|
||||
/// The Polkadot network ID. This is named.
|
||||
pub const PolkadotNetwork: NetworkId = NetworkId::Polkadot;
|
||||
/// Our XCM location ancestry - i.e. what, if anything, `Parent` means evaluated in our context. Since
|
||||
/// Polkadot is a top-level relay-chain, there is no ancestry.
|
||||
pub const Ancestry: MultiLocation = Here.into();
|
||||
/// The check account, which holds any native assets that have been teleported out and not back in (yet).
|
||||
pub const ThisNetwork: NetworkId = NetworkId::Polkadot;
|
||||
/// Our location in the universe of consensus systems.
|
||||
pub const UniversalLocation: InteriorMultiLocation = X1(GlobalConsensus(ThisNetwork::get()));
|
||||
/// The Checking Account, which holds any native assets that have been teleported out and not back in (yet).
|
||||
pub CheckAccount: AccountId = XcmPallet::check_account();
|
||||
/// The Checking Account along with the indication that the local chain is able to mint tokens.
|
||||
pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local);
|
||||
}
|
||||
|
||||
/// The canonical means of converting a `MultiLocation` into an `AccountId`, used when we want to determine
|
||||
@@ -54,24 +58,24 @@ pub type SovereignAccountOf = (
|
||||
// We can convert a child parachain using the standard `AccountId` conversion.
|
||||
ChildParachainConvertsVia<ParaId, AccountId>,
|
||||
// We can directly alias an `AccountId32` into a local account.
|
||||
AccountId32Aliases<PolkadotNetwork, AccountId>,
|
||||
AccountId32Aliases<ThisNetwork, AccountId>,
|
||||
);
|
||||
|
||||
/// Our asset transactor. This is what allows us to interact with the runtime assets from the point of
|
||||
/// view of XCM-only concepts like `MultiLocation` and `MultiAsset`.
|
||||
///
|
||||
/// Ours is only aware of the Balances pallet, which is mapped to `DotLocation`.
|
||||
/// Ours is only aware of the Balances pallet, which is mapped to `TokenLocation`.
|
||||
pub type LocalAssetTransactor = XcmCurrencyAdapter<
|
||||
// Use this currency:
|
||||
Balances,
|
||||
// Use this currency when it is a fungible asset matching the given location or name:
|
||||
IsConcrete<DotLocation>,
|
||||
IsConcrete<TokenLocation>,
|
||||
// We can convert the MultiLocations with our converter above:
|
||||
SovereignAccountOf,
|
||||
// Our chain's account ID type (we can't get away without mentioning it explicitly):
|
||||
AccountId,
|
||||
// We track our teleports in/out to keep total issuance correct.
|
||||
CheckAccount,
|
||||
LocalCheckAccount,
|
||||
>;
|
||||
|
||||
/// The means that we convert an XCM origin `MultiLocation` into the runtime's `Origin` type for
|
||||
@@ -86,12 +90,12 @@ type LocalOriginConverter = (
|
||||
ChildParachainAsNative<parachains_origin::Origin, RuntimeOrigin>,
|
||||
// If the origin kind is `Native` and the XCM origin is the `AccountId32` location, then it can
|
||||
// be expressed using the `Signed` origin variant.
|
||||
SignedAccountId32AsNative<PolkadotNetwork, RuntimeOrigin>,
|
||||
SignedAccountId32AsNative<ThisNetwork, RuntimeOrigin>,
|
||||
);
|
||||
|
||||
parameter_types! {
|
||||
/// The amount of weight an XCM operation takes. This is a safe overestimate.
|
||||
pub const BaseXcmWeight: u64 = 1_000_000_000;
|
||||
pub const BaseXcmWeight: Weight = Weight::from_parts(1_000_000_000, 64 * 1024);
|
||||
/// Maximum number of instructions in a single XCM fragment. A sanity check against weight
|
||||
/// calculations getting too crazy.
|
||||
pub const MaxInstructions: u32 = 100;
|
||||
@@ -101,18 +105,19 @@ parameter_types! {
|
||||
/// individual routers.
|
||||
pub type XcmRouter = (
|
||||
// Only one router so far - use DMP to communicate with child parachains.
|
||||
xcm_sender::ChildParachainRouter<Runtime, XcmPallet>,
|
||||
xcm_sender::ChildParachainRouter<Runtime, XcmPallet, ()>,
|
||||
);
|
||||
|
||||
parameter_types! {
|
||||
pub const Polkadot: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(DotLocation::get()) });
|
||||
pub const PolkadotForStatemint: (MultiAssetFilter, MultiLocation) = (Polkadot::get(), Parachain(1000).into());
|
||||
pub const PolkadotForCollectives: (MultiAssetFilter, MultiLocation) = (Polkadot::get(), Parachain(1001).into());
|
||||
pub const Dot: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) });
|
||||
pub const DotForStatemint: (MultiAssetFilter, MultiLocation) = (Dot::get(), Parachain(1000).into_location());
|
||||
pub const DotForCollectives: (MultiAssetFilter, MultiLocation) = (Dot::get(), Parachain(1001).into_location());
|
||||
pub const MaxAssetsIntoHolding: u32 = 64;
|
||||
}
|
||||
|
||||
/// Polkadot Relay recognizes/respects System parachains as teleporters.
|
||||
/// Polkadot Relay recognizes/respects the Statemint chain as a teleporter.
|
||||
pub type TrustedTeleporters =
|
||||
(xcm_builder::Case<PolkadotForStatemint>, xcm_builder::Case<PolkadotForCollectives>);
|
||||
(xcm_builder::Case<DotForStatemint>, xcm_builder::Case<DotForCollectives>);
|
||||
|
||||
match_types! {
|
||||
pub type OnlyParachains: impl Contains<MultiLocation> = {
|
||||
@@ -124,14 +129,175 @@ match_types! {
|
||||
pub type Barrier = (
|
||||
// Weight that is paid for may be consumed.
|
||||
TakeWeightCredit,
|
||||
// If the message is one that immediately attemps to pay for execution, then allow it.
|
||||
AllowTopLevelPaidExecutionFrom<Everything>,
|
||||
// Expected responses are OK.
|
||||
AllowKnownQueryResponses<XcmPallet>,
|
||||
// Subscriptions for version tracking are OK.
|
||||
AllowSubscriptionsFrom<OnlyParachains>,
|
||||
WithComputedOrigin<
|
||||
(
|
||||
// If the message is one that immediately attemps to pay for execution, then allow it.
|
||||
AllowTopLevelPaidExecutionFrom<Everything>,
|
||||
// Subscriptions for version tracking are OK.
|
||||
AllowSubscriptionsFrom<OnlyParachains>,
|
||||
),
|
||||
UniversalLocation,
|
||||
ConstU32<8>,
|
||||
>,
|
||||
);
|
||||
|
||||
/// A call filter for the XCM Transact instruction. This is a temporary measure until we
|
||||
/// properly account for proof size weights.
|
||||
///
|
||||
/// Calls that are allowed through this filter must:
|
||||
/// 1. Have a fixed weight;
|
||||
/// 2. Cannot lead to another call being made;
|
||||
/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call parameters.
|
||||
pub struct SafeCallFilter;
|
||||
impl Contains<RuntimeCall> for SafeCallFilter {
|
||||
fn contains(call: &RuntimeCall) -> bool {
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
{
|
||||
if matches!(call, RuntimeCall::System(frame_system::Call::remark_with_event { .. })) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
match call {
|
||||
RuntimeCall::System(
|
||||
frame_system::Call::kill_prefix { .. } | frame_system::Call::set_heap_pages { .. },
|
||||
) |
|
||||
RuntimeCall::Babe(..) |
|
||||
RuntimeCall::Timestamp(..) |
|
||||
RuntimeCall::Indices(..) |
|
||||
RuntimeCall::Balances(..) |
|
||||
RuntimeCall::Staking(
|
||||
pallet_staking::Call::bond { .. } |
|
||||
pallet_staking::Call::bond_extra { .. } |
|
||||
pallet_staking::Call::unbond { .. } |
|
||||
pallet_staking::Call::withdraw_unbonded { .. } |
|
||||
pallet_staking::Call::validate { .. } |
|
||||
pallet_staking::Call::nominate { .. } |
|
||||
pallet_staking::Call::chill { .. } |
|
||||
pallet_staking::Call::set_payee { .. } |
|
||||
pallet_staking::Call::set_controller { .. } |
|
||||
pallet_staking::Call::set_validator_count { .. } |
|
||||
pallet_staking::Call::increase_validator_count { .. } |
|
||||
pallet_staking::Call::scale_validator_count { .. } |
|
||||
pallet_staking::Call::force_no_eras { .. } |
|
||||
pallet_staking::Call::force_new_era { .. } |
|
||||
pallet_staking::Call::set_invulnerables { .. } |
|
||||
pallet_staking::Call::force_unstake { .. } |
|
||||
pallet_staking::Call::force_new_era_always { .. } |
|
||||
pallet_staking::Call::payout_stakers { .. } |
|
||||
pallet_staking::Call::rebond { .. } |
|
||||
pallet_staking::Call::reap_stash { .. } |
|
||||
pallet_staking::Call::set_staking_configs { .. } |
|
||||
pallet_staking::Call::chill_other { .. } |
|
||||
pallet_staking::Call::force_apply_min_commission { .. },
|
||||
) |
|
||||
RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) |
|
||||
RuntimeCall::Grandpa(..) |
|
||||
RuntimeCall::ImOnline(..) |
|
||||
RuntimeCall::Democracy(
|
||||
pallet_democracy::Call::second { .. } |
|
||||
pallet_democracy::Call::vote { .. } |
|
||||
pallet_democracy::Call::emergency_cancel { .. } |
|
||||
pallet_democracy::Call::fast_track { .. } |
|
||||
pallet_democracy::Call::veto_external { .. } |
|
||||
pallet_democracy::Call::cancel_referendum { .. } |
|
||||
pallet_democracy::Call::delegate { .. } |
|
||||
pallet_democracy::Call::undelegate { .. } |
|
||||
pallet_democracy::Call::clear_public_proposals { .. } |
|
||||
pallet_democracy::Call::unlock { .. } |
|
||||
pallet_democracy::Call::remove_vote { .. } |
|
||||
pallet_democracy::Call::remove_other_vote { .. } |
|
||||
pallet_democracy::Call::blacklist { .. } |
|
||||
pallet_democracy::Call::cancel_proposal { .. },
|
||||
) |
|
||||
RuntimeCall::Council(
|
||||
pallet_collective::Call::vote { .. } |
|
||||
pallet_collective::Call::close_old_weight { .. } |
|
||||
pallet_collective::Call::disapprove_proposal { .. } |
|
||||
pallet_collective::Call::close { .. },
|
||||
) |
|
||||
RuntimeCall::TechnicalCommittee(
|
||||
pallet_collective::Call::vote { .. } |
|
||||
pallet_collective::Call::close_old_weight { .. } |
|
||||
pallet_collective::Call::disapprove_proposal { .. } |
|
||||
pallet_collective::Call::close { .. },
|
||||
) |
|
||||
RuntimeCall::PhragmenElection(
|
||||
pallet_elections_phragmen::Call::remove_voter { .. } |
|
||||
pallet_elections_phragmen::Call::submit_candidacy { .. } |
|
||||
pallet_elections_phragmen::Call::renounce_candidacy { .. } |
|
||||
pallet_elections_phragmen::Call::remove_member { .. } |
|
||||
pallet_elections_phragmen::Call::clean_defunct_voters { .. },
|
||||
) |
|
||||
RuntimeCall::TechnicalMembership(
|
||||
pallet_membership::Call::add_member { .. } |
|
||||
pallet_membership::Call::remove_member { .. } |
|
||||
pallet_membership::Call::swap_member { .. } |
|
||||
pallet_membership::Call::change_key { .. } |
|
||||
pallet_membership::Call::set_prime { .. } |
|
||||
pallet_membership::Call::clear_prime { .. },
|
||||
) |
|
||||
RuntimeCall::Treasury(..) |
|
||||
RuntimeCall::Claims(
|
||||
super::claims::Call::claim { .. } |
|
||||
super::claims::Call::mint_claim { .. } |
|
||||
super::claims::Call::move_claim { .. },
|
||||
) |
|
||||
RuntimeCall::Utility(pallet_utility::Call::as_derivative { .. }) |
|
||||
RuntimeCall::Identity(
|
||||
pallet_identity::Call::add_registrar { .. } |
|
||||
pallet_identity::Call::set_identity { .. } |
|
||||
pallet_identity::Call::clear_identity { .. } |
|
||||
pallet_identity::Call::request_judgement { .. } |
|
||||
pallet_identity::Call::cancel_request { .. } |
|
||||
pallet_identity::Call::set_fee { .. } |
|
||||
pallet_identity::Call::set_account_id { .. } |
|
||||
pallet_identity::Call::set_fields { .. } |
|
||||
pallet_identity::Call::provide_judgement { .. } |
|
||||
pallet_identity::Call::kill_identity { .. } |
|
||||
pallet_identity::Call::add_sub { .. } |
|
||||
pallet_identity::Call::rename_sub { .. } |
|
||||
pallet_identity::Call::remove_sub { .. } |
|
||||
pallet_identity::Call::quit_sub { .. },
|
||||
) |
|
||||
RuntimeCall::Vesting(..) |
|
||||
RuntimeCall::Bounties(
|
||||
pallet_bounties::Call::propose_bounty { .. } |
|
||||
pallet_bounties::Call::approve_bounty { .. } |
|
||||
pallet_bounties::Call::propose_curator { .. } |
|
||||
pallet_bounties::Call::unassign_curator { .. } |
|
||||
pallet_bounties::Call::accept_curator { .. } |
|
||||
pallet_bounties::Call::award_bounty { .. } |
|
||||
pallet_bounties::Call::claim_bounty { .. } |
|
||||
pallet_bounties::Call::close_bounty { .. },
|
||||
) |
|
||||
RuntimeCall::ChildBounties(..) |
|
||||
RuntimeCall::ElectionProviderMultiPhase(..) |
|
||||
RuntimeCall::VoterList(..) |
|
||||
RuntimeCall::NominationPools(
|
||||
pallet_nomination_pools::Call::join { .. } |
|
||||
pallet_nomination_pools::Call::bond_extra { .. } |
|
||||
pallet_nomination_pools::Call::claim_payout { .. } |
|
||||
pallet_nomination_pools::Call::unbond { .. } |
|
||||
pallet_nomination_pools::Call::pool_withdraw_unbonded { .. } |
|
||||
pallet_nomination_pools::Call::withdraw_unbonded { .. } |
|
||||
pallet_nomination_pools::Call::create { .. } |
|
||||
pallet_nomination_pools::Call::create_with_pool_id { .. } |
|
||||
pallet_nomination_pools::Call::set_state { .. } |
|
||||
pallet_nomination_pools::Call::set_configs { .. } |
|
||||
pallet_nomination_pools::Call::update_roles { .. } |
|
||||
pallet_nomination_pools::Call::chill { .. },
|
||||
) |
|
||||
RuntimeCall::XcmPallet(pallet_xcm::Call::limited_reserve_transfer_assets {
|
||||
..
|
||||
}) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct XcmConfig;
|
||||
impl xcm_executor::Config for XcmConfig {
|
||||
type RuntimeCall = RuntimeCall;
|
||||
@@ -141,21 +307,35 @@ impl xcm_executor::Config for XcmConfig {
|
||||
// Polkadot Relay recognises no chains which act as reserves.
|
||||
type IsReserve = ();
|
||||
type IsTeleporter = TrustedTeleporters;
|
||||
type LocationInverter = LocationInverter<Ancestry>;
|
||||
type UniversalLocation = UniversalLocation;
|
||||
type Barrier = Barrier;
|
||||
type Weigher = FixedWeightBounds<BaseXcmWeight, RuntimeCall, MaxInstructions>;
|
||||
// The weight trader piggybacks on the existing transaction-fee conversion logic.
|
||||
type Trader = UsingComponents<WeightToFee, DotLocation, AccountId, Balances, ToAuthor<Runtime>>;
|
||||
type Trader =
|
||||
UsingComponents<WeightToFee, TokenLocation, AccountId, Balances, ToAuthor<Runtime>>;
|
||||
type ResponseHandler = XcmPallet;
|
||||
type AssetTrap = XcmPallet;
|
||||
type AssetLocker = ();
|
||||
type AssetExchanger = ();
|
||||
type AssetClaims = XcmPallet;
|
||||
type SubscriptionService = XcmPallet;
|
||||
type PalletInstancesInfo = AllPalletsWithSystem;
|
||||
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
|
||||
type FeeManager = ();
|
||||
// No bridges yet...
|
||||
type MessageExporter = ();
|
||||
type UniversalAliases = Nothing;
|
||||
type CallDispatcher = WithOriginFilter<SafeCallFilter>;
|
||||
type SafeCallFilter = SafeCallFilter;
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const CouncilBodyId: BodyId = BodyId::Executive;
|
||||
// We are conservative with the XCM version we advertize.
|
||||
pub const AdvertisedXcmVersion: u32 = 2;
|
||||
}
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
parameter_types! {
|
||||
pub ReachableDest: Option<MultiLocation> = Some(Parachain(1000).into());
|
||||
}
|
||||
|
||||
/// Type to convert a council origin to a Plurality `MultiLocation` value.
|
||||
@@ -172,7 +352,7 @@ pub type LocalOriginToLocation = (
|
||||
// `Unit` body.
|
||||
CouncilToPlurality,
|
||||
// And a usual Signed origin to be used in XCM as a corresponding AccountId32
|
||||
SignedToAccountId32<RuntimeOrigin, AccountId, PolkadotNetwork>,
|
||||
SignedToAccountId32<RuntimeOrigin, AccountId, ThisNetwork>,
|
||||
);
|
||||
|
||||
impl pallet_xcm::Config for Runtime {
|
||||
@@ -188,9 +368,17 @@ impl pallet_xcm::Config for Runtime {
|
||||
type XcmTeleportFilter = Everything; // == Allow All
|
||||
type XcmReserveTransferFilter = Everything; // == Allow All
|
||||
type Weigher = FixedWeightBounds<BaseXcmWeight, RuntimeCall, MaxInstructions>;
|
||||
type LocationInverter = LocationInverter<Ancestry>;
|
||||
type UniversalLocation = UniversalLocation;
|
||||
type RuntimeOrigin = RuntimeOrigin;
|
||||
type RuntimeCall = RuntimeCall;
|
||||
const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
|
||||
type AdvertisedXcmVersion = AdvertisedXcmVersion;
|
||||
type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
|
||||
type Currency = Balances;
|
||||
type CurrencyMatcher = ();
|
||||
type TrustedLockers = ();
|
||||
type SovereignAccountOf = SovereignAccountOf;
|
||||
type MaxLockers = ConstU32<8>;
|
||||
type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type ReachableDest = ReachableDest;
|
||||
}
|
||||
|
||||
@@ -1488,6 +1488,9 @@ pub type Migrations = (
|
||||
pallet_scheduler::migration::v4::CleanupAgendas<Runtime>,
|
||||
parachains_disputes::migration::v1::MigrateToV1<Runtime>,
|
||||
parachains_configuration::migration::v4::MigrateToV4<Runtime>,
|
||||
// "Use 2D weights in XCM v3" <https://github.com/paritytech/polkadot/pull/6134>
|
||||
pallet_xcm::migration::v1::MigrateToV1<Runtime>,
|
||||
parachains_ump::migration::v1::MigrateToV1<Runtime>,
|
||||
);
|
||||
|
||||
/// Executive: handles dispatch to the various modules.
|
||||
@@ -1576,6 +1579,7 @@ mod benches {
|
||||
[pallet_utility, Utility]
|
||||
[pallet_vesting, Vesting]
|
||||
// XCM
|
||||
[pallet_xcm, XcmPallet]
|
||||
[pallet_xcm_benchmarks::fungible, pallet_xcm_benchmarks::fungible::Pallet::<Runtime>]
|
||||
[pallet_xcm_benchmarks::generic, pallet_xcm_benchmarks::generic::Pallet::<Runtime>]
|
||||
);
|
||||
@@ -1979,20 +1983,22 @@ sp_api::impl_runtime_apis! {
|
||||
use frame_system_benchmarking::Pallet as SystemBench;
|
||||
use frame_benchmarking::baseline::Pallet as Baseline;
|
||||
use xcm::latest::prelude::*;
|
||||
use xcm_config::{CheckAccount, RocLocation, SovereignAccountOf, Statemine, XcmConfig};
|
||||
use xcm_config::{
|
||||
LocalCheckAccount, LocationConverter, Statemine, TokenLocation, XcmConfig,
|
||||
};
|
||||
|
||||
impl frame_system_benchmarking::Config for Runtime {}
|
||||
impl frame_benchmarking::baseline::Config for Runtime {}
|
||||
impl pallet_xcm_benchmarks::Config for Runtime {
|
||||
type XcmConfig = XcmConfig;
|
||||
type AccountIdConverter = SovereignAccountOf;
|
||||
type AccountIdConverter = LocationConverter;
|
||||
fn valid_destination() -> Result<MultiLocation, BenchmarkError> {
|
||||
Ok(Statemine::get())
|
||||
}
|
||||
fn worst_case_holding() -> MultiAssets {
|
||||
fn worst_case_holding(_depositable_count: u32) -> MultiAssets {
|
||||
// Rococo only knows about ROC
|
||||
vec![MultiAsset{
|
||||
id: Concrete(RocLocation::get()),
|
||||
id: Concrete(TokenLocation::get()),
|
||||
fun: Fungible(1_000_000 * UNITS),
|
||||
}].into()
|
||||
}
|
||||
@@ -2001,24 +2007,23 @@ sp_api::impl_runtime_apis! {
|
||||
parameter_types! {
|
||||
pub const TrustedTeleporter: Option<(MultiLocation, MultiAsset)> = Some((
|
||||
Statemine::get(),
|
||||
MultiAsset { fun: Fungible(1 * UNITS), id: Concrete(RocLocation::get()) },
|
||||
MultiAsset { fun: Fungible(1 * UNITS), id: Concrete(TokenLocation::get()) },
|
||||
));
|
||||
pub const TrustedReserve: Option<(MultiLocation, MultiAsset)> = Some((
|
||||
Statemine::get(),
|
||||
MultiAsset { fun: Fungible(1 * UNITS), id: Concrete(RocLocation::get()) },
|
||||
MultiAsset { fun: Fungible(1 * UNITS), id: Concrete(TokenLocation::get()) },
|
||||
));
|
||||
}
|
||||
|
||||
impl pallet_xcm_benchmarks::fungible::Config for Runtime {
|
||||
type TransactAsset = Balances;
|
||||
|
||||
type CheckedAccount = CheckAccount;
|
||||
type CheckedAccount = LocalCheckAccount;
|
||||
type TrustedTeleporter = TrustedTeleporter;
|
||||
type TrustedReserve = TrustedReserve;
|
||||
|
||||
fn get_multi_asset() -> MultiAsset {
|
||||
MultiAsset {
|
||||
id: Concrete(RocLocation::get()),
|
||||
id: Concrete(TokenLocation::get()),
|
||||
fun: Fungible(1 * UNITS),
|
||||
}
|
||||
}
|
||||
@@ -2031,8 +2036,18 @@ sp_api::impl_runtime_apis! {
|
||||
(0u64, Response::Version(Default::default()))
|
||||
}
|
||||
|
||||
fn transact_origin() -> Result<MultiLocation, BenchmarkError> {
|
||||
Ok(Statemine::get())
|
||||
fn worst_case_asset_exchange() -> Result<(MultiAssets, MultiAssets), BenchmarkError> {
|
||||
// Rococo doesn't support asset exchanges
|
||||
Err(BenchmarkError::Skip)
|
||||
}
|
||||
|
||||
fn universal_alias() -> Result<Junction, BenchmarkError> {
|
||||
// The XCM executor of Rococo doesn't have a configured `UniversalAliases`
|
||||
Err(BenchmarkError::Skip)
|
||||
}
|
||||
|
||||
fn transact_origin_and_runtime_call() -> Result<(MultiLocation, RuntimeCall), BenchmarkError> {
|
||||
Ok((Statemine::get(), frame_system::Call::remark_with_event { remark: vec![] }.into()))
|
||||
}
|
||||
|
||||
fn subscribe_origin() -> Result<MultiLocation, BenchmarkError> {
|
||||
@@ -2041,10 +2056,15 @@ sp_api::impl_runtime_apis! {
|
||||
|
||||
fn claimable_asset() -> Result<(MultiLocation, MultiLocation, MultiAssets), BenchmarkError> {
|
||||
let origin = Statemine::get();
|
||||
let assets: MultiAssets = (Concrete(RocLocation::get()), 1_000 * UNITS).into();
|
||||
let assets: MultiAssets = (Concrete(TokenLocation::get()), 1_000 * UNITS).into();
|
||||
let ticket = MultiLocation { parents: 0, interior: Here };
|
||||
Ok((origin, ticket, assets))
|
||||
}
|
||||
|
||||
fn unlockable_asset() -> Result<(MultiLocation, MultiLocation, MultiAsset), BenchmarkError> {
|
||||
// Rococo doesn't support asset locking
|
||||
Err(BenchmarkError::Skip)
|
||||
}
|
||||
}
|
||||
|
||||
let whitelist: Vec<TrackedStorageKey> = vec![
|
||||
|
||||
@@ -39,6 +39,7 @@ pub mod pallet_tips;
|
||||
pub mod pallet_treasury;
|
||||
pub mod pallet_utility;
|
||||
pub mod pallet_vesting;
|
||||
pub mod pallet_xcm;
|
||||
pub mod runtime_common_auctions;
|
||||
pub mod runtime_common_claims;
|
||||
pub mod runtime_common_crowdloan;
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
// Copyright 2017-2022 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/>.
|
||||
//! Autogenerated weights for `pallet_xcm`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2022-12-16, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024
|
||||
|
||||
// Executed Command:
|
||||
// /home/benchbot/cargo_target_dir/production/polkadot
|
||||
// benchmark
|
||||
// pallet
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
// --extrinsic=*
|
||||
// --execution=wasm
|
||||
// --wasm-execution=compiled
|
||||
// --heap-pages=4096
|
||||
// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/polkadot/.git/.artifacts/bench.json
|
||||
// --pallet=pallet_xcm
|
||||
// --chain=rococo-dev
|
||||
// --header=./file_header.txt
|
||||
// --output=./runtime/rococo/src/weights/
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use frame_support::{traits::Get, weights::Weight};
|
||||
use sp_std::marker::PhantomData;
|
||||
|
||||
/// Weight functions for `pallet_xcm`.
|
||||
pub struct WeightInfo<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
fn send() -> Weight {
|
||||
// Minimum execution time: 36_707 nanoseconds.
|
||||
Weight::from_ref_time(37_718_000)
|
||||
.saturating_add(T::DbWeight::get().reads(6))
|
||||
.saturating_add(T::DbWeight::get().writes(3))
|
||||
}
|
||||
fn teleport_assets() -> Weight {
|
||||
// Minimum execution time: 28_720 nanoseconds.
|
||||
Weight::from_ref_time(29_098_000)
|
||||
}
|
||||
fn reserve_transfer_assets() -> Weight {
|
||||
// Minimum execution time: 27_702 nanoseconds.
|
||||
Weight::from_ref_time(28_517_000)
|
||||
}
|
||||
fn execute() -> Weight {
|
||||
// Minimum execution time: 14_527 nanoseconds.
|
||||
Weight::from_ref_time(14_823_000)
|
||||
}
|
||||
// Storage: XcmPallet SupportedVersion (r:0 w:1)
|
||||
fn force_xcm_version() -> Weight {
|
||||
// Minimum execution time: 16_306 nanoseconds.
|
||||
Weight::from_ref_time(16_619_000)
|
||||
.saturating_add(T::DbWeight::get().writes(1))
|
||||
}
|
||||
// Storage: XcmPallet SafeXcmVersion (r:0 w:1)
|
||||
fn force_default_xcm_version() -> Weight {
|
||||
// Minimum execution time: 4_911 nanoseconds.
|
||||
Weight::from_ref_time(5_080_000)
|
||||
.saturating_add(T::DbWeight::get().writes(1))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifiers (r:1 w:1)
|
||||
// Storage: XcmPallet QueryCounter (r:1 w:1)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
// Storage: XcmPallet Queries (r:0 w:1)
|
||||
fn force_subscribe_version_notify() -> Weight {
|
||||
// Minimum execution time: 48_258 nanoseconds.
|
||||
Weight::from_ref_time(49_130_000)
|
||||
.saturating_add(T::DbWeight::get().reads(8))
|
||||
.saturating_add(T::DbWeight::get().writes(6))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifiers (r:1 w:1)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
// Storage: XcmPallet Queries (r:0 w:1)
|
||||
fn force_unsubscribe_version_notify() -> Weight {
|
||||
// Minimum execution time: 52_381 nanoseconds.
|
||||
Weight::from_ref_time(53_183_000)
|
||||
.saturating_add(T::DbWeight::get().reads(7))
|
||||
.saturating_add(T::DbWeight::get().writes(5))
|
||||
}
|
||||
// Storage: XcmPallet SupportedVersion (r:4 w:2)
|
||||
fn migrate_supported_version() -> Weight {
|
||||
// Minimum execution time: 16_915 nanoseconds.
|
||||
Weight::from_ref_time(17_479_000)
|
||||
.saturating_add(T::DbWeight::get().reads(4))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifiers (r:4 w:2)
|
||||
fn migrate_version_notifiers() -> Weight {
|
||||
// Minimum execution time: 17_012 nanoseconds.
|
||||
Weight::from_ref_time(17_319_000)
|
||||
.saturating_add(T::DbWeight::get().reads(4))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifyTargets (r:5 w:0)
|
||||
fn already_notified_target() -> Weight {
|
||||
// Minimum execution time: 19_489 nanoseconds.
|
||||
Weight::from_ref_time(19_995_000)
|
||||
.saturating_add(T::DbWeight::get().reads(5))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifyTargets (r:2 w:1)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
fn notify_current_targets() -> Weight {
|
||||
// Minimum execution time: 43_334 nanoseconds.
|
||||
Weight::from_ref_time(43_983_000)
|
||||
.saturating_add(T::DbWeight::get().reads(8))
|
||||
.saturating_add(T::DbWeight::get().writes(4))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifyTargets (r:3 w:0)
|
||||
fn notify_target_migration_fail() -> Weight {
|
||||
// Minimum execution time: 8_627 nanoseconds.
|
||||
Weight::from_ref_time(8_860_000)
|
||||
.saturating_add(T::DbWeight::get().reads(3))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifyTargets (r:4 w:2)
|
||||
fn migrate_version_notify_targets() -> Weight {
|
||||
// Minimum execution time: 17_679 nanoseconds.
|
||||
Weight::from_ref_time(18_042_000)
|
||||
.saturating_add(T::DbWeight::get().reads(4))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifyTargets (r:4 w:2)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
fn migrate_and_notify_old_targets() -> Weight {
|
||||
// Minimum execution time: 45_445 nanoseconds.
|
||||
Weight::from_ref_time(48_369_000)
|
||||
.saturating_add(T::DbWeight::get().reads(10))
|
||||
.saturating_add(T::DbWeight::get().writes(5))
|
||||
}
|
||||
}
|
||||
@@ -16,23 +16,25 @@
|
||||
//! Autogenerated weights for `runtime_parachains::ump`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2022-11-16, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
|
||||
//! DATE: 2023-01-16, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024
|
||||
|
||||
// Executed Command:
|
||||
// ./target/production/polkadot
|
||||
// /home/benchbot/cargo_target_dir/production/polkadot
|
||||
// benchmark
|
||||
// pallet
|
||||
// --chain=rococo-dev
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
// --pallet=runtime_parachains::ump
|
||||
// --extrinsic=*
|
||||
// --execution=wasm
|
||||
// --wasm-execution=compiled
|
||||
// --heap-pages=4096
|
||||
// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/polkadot/.git/.artifacts/bench.json
|
||||
// --pallet=runtime_parachains::ump
|
||||
// --chain=rococo-dev
|
||||
// --header=./file_header.txt
|
||||
// --output=./runtime/rococo/src/weights/runtime_parachains_ump.rs
|
||||
// --output=./runtime/rococo/src/weights/
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
@@ -46,26 +48,27 @@ pub struct WeightInfo<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> runtime_parachains::ump::WeightInfo for WeightInfo<T> {
|
||||
/// The range of component `s` is `[0, 51200]`.
|
||||
fn process_upward_message(s: u32, ) -> Weight {
|
||||
// Minimum execution time: 10_433 nanoseconds.
|
||||
Weight::from_ref_time(6_809_084 as u64)
|
||||
// Standard Error: 12
|
||||
.saturating_add(Weight::from_ref_time(1_973 as u64).saturating_mul(s as u64))
|
||||
// Minimum execution time: 10_224 nanoseconds.
|
||||
Weight::from_ref_time(4_699_572)
|
||||
// Standard Error: 11
|
||||
.saturating_add(Weight::from_ref_time(1_907).saturating_mul(s.into()))
|
||||
}
|
||||
// Storage: Ump NeedsDispatch (r:1 w:1)
|
||||
// Storage: Ump NextDispatchRoundStartWith (r:1 w:1)
|
||||
// Storage: Ump RelayDispatchQueues (r:0 w:1)
|
||||
// Storage: Ump RelayDispatchQueueSize (r:0 w:1)
|
||||
fn clean_ump_after_outgoing() -> Weight {
|
||||
// Minimum execution time: 8_932 nanoseconds.
|
||||
Weight::from_ref_time(9_171_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(2 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(4 as u64))
|
||||
// Minimum execution time: 9_180 nanoseconds.
|
||||
Weight::from_ref_time(9_354_000)
|
||||
.saturating_add(T::DbWeight::get().reads(2))
|
||||
.saturating_add(T::DbWeight::get().writes(4))
|
||||
}
|
||||
// Storage: Ump Overweight (r:1 w:1)
|
||||
// Storage: Ump CounterForOverweight (r:1 w:1)
|
||||
fn service_overweight() -> Weight {
|
||||
// Minimum execution time: 25_129 nanoseconds.
|
||||
Weight::from_ref_time(25_441_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(1 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as u64))
|
||||
// Minimum execution time: 28_704 nanoseconds.
|
||||
Weight::from_ref_time(29_057_000)
|
||||
.saturating_add(T::DbWeight::get().reads(2))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,7 @@ mod pallet_xcm_benchmarks_generic;
|
||||
use crate::Runtime;
|
||||
use frame_support::weights::Weight;
|
||||
use sp_std::prelude::*;
|
||||
use xcm::{
|
||||
latest::{prelude::*, Weight as XCMWeight},
|
||||
DoubleEncoded,
|
||||
};
|
||||
use xcm::{latest::prelude::*, DoubleEncoded};
|
||||
|
||||
use pallet_xcm_benchmarks_fungible::WeightInfo as XcmBalancesWeight;
|
||||
use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric;
|
||||
@@ -31,15 +28,15 @@ impl From<&MultiAsset> for AssetTypes {
|
||||
}
|
||||
|
||||
trait WeighMultiAssets {
|
||||
fn weigh_multi_assets(&self, balances_weight: Weight) -> XCMWeight;
|
||||
fn weigh_multi_assets(&self, balances_weight: Weight) -> Weight;
|
||||
}
|
||||
|
||||
// Rococo only knows about one asset, the balances pallet.
|
||||
const MAX_ASSETS: u32 = 1;
|
||||
|
||||
impl WeighMultiAssets for MultiAssetFilter {
|
||||
fn weigh_multi_assets(&self, balances_weight: Weight) -> XCMWeight {
|
||||
let weight = match self {
|
||||
fn weigh_multi_assets(&self, balances_weight: Weight) -> Weight {
|
||||
match self {
|
||||
Self::Definite(assets) => assets
|
||||
.inner()
|
||||
.into_iter()
|
||||
@@ -49,155 +46,213 @@ impl WeighMultiAssets for MultiAssetFilter {
|
||||
AssetTypes::Unknown => Weight::MAX,
|
||||
})
|
||||
.fold(Weight::zero(), |acc, x| acc.saturating_add(x)),
|
||||
Self::Wild(_) => balances_weight.saturating_mul(MAX_ASSETS as u64),
|
||||
};
|
||||
|
||||
weight.ref_time()
|
||||
Self::Wild(AllOf { .. } | AllOfCounted { .. }) => balances_weight,
|
||||
Self::Wild(AllCounted(count)) => balances_weight.saturating_mul(*count as u64),
|
||||
Self::Wild(All) => balances_weight.saturating_mul(MAX_ASSETS as u64),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WeighMultiAssets for MultiAssets {
|
||||
fn weigh_multi_assets(&self, balances_weight: Weight) -> XCMWeight {
|
||||
let weight = self
|
||||
.inner()
|
||||
fn weigh_multi_assets(&self, balances_weight: Weight) -> Weight {
|
||||
self.inner()
|
||||
.into_iter()
|
||||
.map(|m| <AssetTypes as From<&MultiAsset>>::from(m))
|
||||
.map(|t| match t {
|
||||
AssetTypes::Balances => balances_weight,
|
||||
AssetTypes::Unknown => Weight::MAX,
|
||||
})
|
||||
.fold(Weight::zero(), |acc, x| acc.saturating_add(x));
|
||||
|
||||
weight.ref_time()
|
||||
.fold(Weight::zero(), |acc, x| acc.saturating_add(x))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RococoXcmWeight<Call>(core::marker::PhantomData<Call>);
|
||||
impl<Call> XcmWeightInfo<Call> for RococoXcmWeight<Call> {
|
||||
fn withdraw_asset(assets: &MultiAssets) -> XCMWeight {
|
||||
pub struct RococoXcmWeight<RuntimeCall>(core::marker::PhantomData<RuntimeCall>);
|
||||
impl<RuntimeCall> XcmWeightInfo<RuntimeCall> for RococoXcmWeight<RuntimeCall> {
|
||||
fn withdraw_asset(assets: &MultiAssets) -> Weight {
|
||||
assets.weigh_multi_assets(XcmBalancesWeight::<Runtime>::withdraw_asset())
|
||||
}
|
||||
fn reserve_asset_deposited(assets: &MultiAssets) -> XCMWeight {
|
||||
fn reserve_asset_deposited(assets: &MultiAssets) -> Weight {
|
||||
assets.weigh_multi_assets(XcmBalancesWeight::<Runtime>::reserve_asset_deposited())
|
||||
}
|
||||
fn receive_teleported_asset(assets: &MultiAssets) -> XCMWeight {
|
||||
fn receive_teleported_asset(assets: &MultiAssets) -> Weight {
|
||||
assets.weigh_multi_assets(XcmBalancesWeight::<Runtime>::receive_teleported_asset())
|
||||
}
|
||||
fn query_response(_query_id: &u64, _response: &Response, _max_weight: &u64) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::query_response().ref_time()
|
||||
fn query_response(
|
||||
_query_id: &u64,
|
||||
_response: &Response,
|
||||
_max_weight: &Weight,
|
||||
_querier: &Option<MultiLocation>,
|
||||
) -> Weight {
|
||||
XcmGeneric::<Runtime>::query_response()
|
||||
}
|
||||
fn transfer_asset(assets: &MultiAssets, _dest: &MultiLocation) -> XCMWeight {
|
||||
fn transfer_asset(assets: &MultiAssets, _dest: &MultiLocation) -> Weight {
|
||||
assets.weigh_multi_assets(XcmBalancesWeight::<Runtime>::transfer_asset())
|
||||
}
|
||||
fn transfer_reserve_asset(
|
||||
assets: &MultiAssets,
|
||||
_dest: &MultiLocation,
|
||||
_xcm: &Xcm<()>,
|
||||
) -> XCMWeight {
|
||||
) -> Weight {
|
||||
assets.weigh_multi_assets(XcmBalancesWeight::<Runtime>::transfer_reserve_asset())
|
||||
}
|
||||
fn transact(
|
||||
_origin_type: &OriginKind,
|
||||
_require_weight_at_most: &u64,
|
||||
_call: &DoubleEncoded<Call>,
|
||||
) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::transact().ref_time()
|
||||
_origin_kind: &OriginKind,
|
||||
_require_weight_at_most: &Weight,
|
||||
_call: &DoubleEncoded<RuntimeCall>,
|
||||
) -> Weight {
|
||||
XcmGeneric::<Runtime>::transact()
|
||||
}
|
||||
fn hrmp_new_channel_open_request(
|
||||
_sender: &u32,
|
||||
_max_message_size: &u32,
|
||||
_max_capacity: &u32,
|
||||
) -> XCMWeight {
|
||||
) -> Weight {
|
||||
// XCM Executor does not currently support HRMP channel operations
|
||||
Weight::MAX.ref_time()
|
||||
Weight::MAX
|
||||
}
|
||||
fn hrmp_channel_accepted(_recipient: &u32) -> XCMWeight {
|
||||
fn hrmp_channel_accepted(_recipient: &u32) -> Weight {
|
||||
// XCM Executor does not currently support HRMP channel operations
|
||||
Weight::MAX.ref_time()
|
||||
Weight::MAX
|
||||
}
|
||||
fn hrmp_channel_closing(_initiator: &u32, _sender: &u32, _recipient: &u32) -> XCMWeight {
|
||||
fn hrmp_channel_closing(_initiator: &u32, _sender: &u32, _recipient: &u32) -> Weight {
|
||||
// XCM Executor does not currently support HRMP channel operations
|
||||
Weight::MAX.ref_time()
|
||||
Weight::MAX
|
||||
}
|
||||
fn clear_origin() -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::clear_origin().ref_time()
|
||||
fn clear_origin() -> Weight {
|
||||
XcmGeneric::<Runtime>::clear_origin()
|
||||
}
|
||||
fn descend_origin(_who: &InteriorMultiLocation) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::descend_origin().ref_time()
|
||||
fn descend_origin(_who: &InteriorMultiLocation) -> Weight {
|
||||
XcmGeneric::<Runtime>::descend_origin()
|
||||
}
|
||||
fn report_error(
|
||||
_query_id: &QueryId,
|
||||
_dest: &MultiLocation,
|
||||
_max_response_weight: &u64,
|
||||
) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::report_error().ref_time()
|
||||
fn report_error(_query_response_info: &QueryResponseInfo) -> Weight {
|
||||
XcmGeneric::<Runtime>::report_error()
|
||||
}
|
||||
|
||||
fn deposit_asset(
|
||||
assets: &MultiAssetFilter,
|
||||
_max_assets: &u32, // TODO use max assets?
|
||||
_dest: &MultiLocation,
|
||||
) -> XCMWeight {
|
||||
fn deposit_asset(assets: &MultiAssetFilter, _dest: &MultiLocation) -> Weight {
|
||||
assets.weigh_multi_assets(XcmBalancesWeight::<Runtime>::deposit_asset())
|
||||
}
|
||||
fn deposit_reserve_asset(
|
||||
assets: &MultiAssetFilter,
|
||||
_max_assets: &u32, // TODO use max assets?
|
||||
_dest: &MultiLocation,
|
||||
_xcm: &Xcm<()>,
|
||||
) -> XCMWeight {
|
||||
) -> Weight {
|
||||
assets.weigh_multi_assets(XcmBalancesWeight::<Runtime>::deposit_reserve_asset())
|
||||
}
|
||||
fn exchange_asset(_give: &MultiAssetFilter, _receive: &MultiAssets) -> XCMWeight {
|
||||
Weight::MAX.ref_time() // todo fix
|
||||
fn exchange_asset(_give: &MultiAssetFilter, _receive: &MultiAssets, _maximal: &bool) -> Weight {
|
||||
// Rococo does not currently support exchange asset operations
|
||||
Weight::MAX
|
||||
}
|
||||
fn initiate_reserve_withdraw(
|
||||
assets: &MultiAssetFilter,
|
||||
_reserve: &MultiLocation,
|
||||
_xcm: &Xcm<()>,
|
||||
) -> XCMWeight {
|
||||
) -> Weight {
|
||||
assets.weigh_multi_assets(XcmGeneric::<Runtime>::initiate_reserve_withdraw())
|
||||
}
|
||||
fn initiate_teleport(
|
||||
assets: &MultiAssetFilter,
|
||||
_dest: &MultiLocation,
|
||||
_xcm: &Xcm<()>,
|
||||
) -> XCMWeight {
|
||||
) -> Weight {
|
||||
assets.weigh_multi_assets(XcmBalancesWeight::<Runtime>::initiate_teleport())
|
||||
}
|
||||
fn query_holding(
|
||||
_query_id: &u64,
|
||||
_dest: &MultiLocation,
|
||||
_assets: &MultiAssetFilter,
|
||||
_max_response_weight: &u64,
|
||||
) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::query_holding().ref_time()
|
||||
fn report_holding(_response_info: &QueryResponseInfo, _assets: &MultiAssetFilter) -> Weight {
|
||||
XcmGeneric::<Runtime>::report_holding()
|
||||
}
|
||||
fn buy_execution(_fees: &MultiAsset, _weight_limit: &WeightLimit) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::buy_execution().ref_time()
|
||||
fn buy_execution(_fees: &MultiAsset, _weight_limit: &WeightLimit) -> Weight {
|
||||
XcmGeneric::<Runtime>::buy_execution()
|
||||
}
|
||||
fn refund_surplus() -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::refund_surplus().ref_time()
|
||||
fn refund_surplus() -> Weight {
|
||||
XcmGeneric::<Runtime>::refund_surplus()
|
||||
}
|
||||
fn set_error_handler(_xcm: &Xcm<Call>) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::set_error_handler().ref_time()
|
||||
fn set_error_handler(_xcm: &Xcm<RuntimeCall>) -> Weight {
|
||||
XcmGeneric::<Runtime>::set_error_handler()
|
||||
}
|
||||
fn set_appendix(_xcm: &Xcm<Call>) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::set_appendix().ref_time()
|
||||
fn set_appendix(_xcm: &Xcm<RuntimeCall>) -> Weight {
|
||||
XcmGeneric::<Runtime>::set_appendix()
|
||||
}
|
||||
fn clear_error() -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::clear_error().ref_time()
|
||||
fn clear_error() -> Weight {
|
||||
XcmGeneric::<Runtime>::clear_error()
|
||||
}
|
||||
fn claim_asset(_assets: &MultiAssets, _ticket: &MultiLocation) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::claim_asset().ref_time()
|
||||
fn claim_asset(_assets: &MultiAssets, _ticket: &MultiLocation) -> Weight {
|
||||
XcmGeneric::<Runtime>::claim_asset()
|
||||
}
|
||||
fn trap(_code: &u64) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::trap().ref_time()
|
||||
fn trap(_code: &u64) -> Weight {
|
||||
XcmGeneric::<Runtime>::trap()
|
||||
}
|
||||
fn subscribe_version(_query_id: &QueryId, _max_response_weight: &u64) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::subscribe_version().ref_time()
|
||||
fn subscribe_version(_query_id: &QueryId, _max_response_weight: &Weight) -> Weight {
|
||||
XcmGeneric::<Runtime>::subscribe_version()
|
||||
}
|
||||
fn unsubscribe_version() -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::unsubscribe_version().ref_time()
|
||||
fn unsubscribe_version() -> Weight {
|
||||
XcmGeneric::<Runtime>::unsubscribe_version()
|
||||
}
|
||||
fn burn_asset(assets: &MultiAssets) -> Weight {
|
||||
assets.weigh_multi_assets(XcmGeneric::<Runtime>::burn_asset())
|
||||
}
|
||||
fn expect_asset(assets: &MultiAssets) -> Weight {
|
||||
assets.weigh_multi_assets(XcmGeneric::<Runtime>::expect_asset())
|
||||
}
|
||||
fn expect_origin(_origin: &Option<MultiLocation>) -> Weight {
|
||||
XcmGeneric::<Runtime>::expect_origin()
|
||||
}
|
||||
fn expect_error(_error: &Option<(u32, XcmError)>) -> Weight {
|
||||
XcmGeneric::<Runtime>::expect_error()
|
||||
}
|
||||
fn query_pallet(_module_name: &Vec<u8>, _response_info: &QueryResponseInfo) -> Weight {
|
||||
XcmGeneric::<Runtime>::query_pallet()
|
||||
}
|
||||
fn expect_pallet(
|
||||
_index: &u32,
|
||||
_name: &Vec<u8>,
|
||||
_module_name: &Vec<u8>,
|
||||
_crate_major: &u32,
|
||||
_min_crate_minor: &u32,
|
||||
) -> Weight {
|
||||
XcmGeneric::<Runtime>::expect_pallet()
|
||||
}
|
||||
fn report_transact_status(_response_info: &QueryResponseInfo) -> Weight {
|
||||
XcmGeneric::<Runtime>::report_transact_status()
|
||||
}
|
||||
fn clear_transact_status() -> Weight {
|
||||
XcmGeneric::<Runtime>::clear_transact_status()
|
||||
}
|
||||
fn universal_origin(_: &Junction) -> Weight {
|
||||
// Rococo does not currently support universal origin operations
|
||||
Weight::MAX
|
||||
}
|
||||
fn export_message(_: &NetworkId, _: &Junctions, _: &Xcm<()>) -> Weight {
|
||||
Weight::MAX // todo fix
|
||||
}
|
||||
fn lock_asset(_: &MultiAsset, _: &MultiLocation) -> Weight {
|
||||
// Rococo does not currently support asset locking operations
|
||||
Weight::MAX
|
||||
}
|
||||
fn unlock_asset(_: &MultiAsset, _: &MultiLocation) -> Weight {
|
||||
// Rococo does not currently support asset locking operations
|
||||
Weight::MAX
|
||||
}
|
||||
fn note_unlockable(_: &MultiAsset, _: &MultiLocation) -> Weight {
|
||||
// Rococo does not currently support asset locking operations
|
||||
Weight::MAX
|
||||
}
|
||||
fn request_unlock(_: &MultiAsset, _: &MultiLocation) -> Weight {
|
||||
// Rococo does not currently support asset locking operations
|
||||
Weight::MAX
|
||||
}
|
||||
fn set_fees_mode(_: &bool) -> Weight {
|
||||
XcmGeneric::<Runtime>::set_fees_mode()
|
||||
}
|
||||
fn set_topic(_topic: &[u8; 32]) -> Weight {
|
||||
XcmGeneric::<Runtime>::set_topic()
|
||||
}
|
||||
fn clear_topic() -> Weight {
|
||||
XcmGeneric::<Runtime>::clear_topic()
|
||||
}
|
||||
fn alias_origin(_: &MultiLocation) -> Weight {
|
||||
// XCM Executor does not currently support alias origin operations
|
||||
Weight::MAX
|
||||
}
|
||||
fn unpaid_execution(_: &WeightLimit, _: &Option<MultiLocation>) -> Weight {
|
||||
XcmGeneric::<Runtime>::unpaid_execution()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ impl<T: frame_system::Config> WeightInfo<T> {
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
pub(crate) fn query_holding() -> Weight {
|
||||
pub(crate) fn report_holding() -> Weight {
|
||||
Weight::from_ref_time(21_822_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(6 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as u64))
|
||||
@@ -133,4 +133,54 @@ impl<T: frame_system::Config> WeightInfo<T> {
|
||||
.saturating_add(T::DbWeight::get().reads(6 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as u64))
|
||||
}
|
||||
pub(crate) fn burn_asset() -> Weight {
|
||||
Weight::from_ref_time(5_259_000 as u64)
|
||||
}
|
||||
pub(crate) fn expect_asset() -> Weight {
|
||||
Weight::from_ref_time(3_745_000 as u64)
|
||||
}
|
||||
pub(crate) fn expect_origin() -> Weight {
|
||||
Weight::from_ref_time(3_847_000 as u64)
|
||||
}
|
||||
pub(crate) fn expect_error() -> Weight {
|
||||
Weight::from_ref_time(3_633_000 as u64)
|
||||
}
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
pub(crate) fn query_pallet() -> Weight {
|
||||
Weight::from_ref_time(21_645_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(5 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as u64))
|
||||
}
|
||||
pub(crate) fn expect_pallet() -> Weight {
|
||||
Weight::from_ref_time(4_017_000 as u64)
|
||||
}
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
pub(crate) fn report_transact_status() -> Weight {
|
||||
Weight::from_ref_time(20_465_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(5 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as u64))
|
||||
}
|
||||
pub(crate) fn clear_transact_status() -> Weight {
|
||||
Weight::from_ref_time(3_723_000 as u64)
|
||||
}
|
||||
pub(crate) fn set_topic() -> Weight {
|
||||
Weight::from_ref_time(3_687_000 as u64)
|
||||
}
|
||||
pub(crate) fn clear_topic() -> Weight {
|
||||
Weight::from_ref_time(3_654_000 as u64)
|
||||
}
|
||||
pub(crate) fn set_fees_mode() -> Weight {
|
||||
Weight::from_ref_time(3_721_000 as u64)
|
||||
}
|
||||
pub(crate) fn unpaid_execution() -> Weight {
|
||||
Weight::from_ref_time(3_111_000 as u64)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,44 +17,37 @@
|
||||
//! XCM configuration for Rococo.
|
||||
|
||||
use super::{
|
||||
parachains_origin, AccountId, Balances, CouncilCollective, ParaId, Runtime, RuntimeCall,
|
||||
RuntimeEvent, RuntimeOrigin, WeightToFee, XcmPallet,
|
||||
parachains_origin, AccountId, AllPalletsWithSystem, Balances, CouncilCollective, ParaId,
|
||||
Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmPallet,
|
||||
};
|
||||
use frame_support::{
|
||||
match_types, parameter_types,
|
||||
traits::{Contains, Everything, Nothing},
|
||||
weights::Weight,
|
||||
};
|
||||
use frame_support::{match_types, parameter_types, traits::Everything};
|
||||
use runtime_common::{xcm_sender, ToAuthor};
|
||||
use sp_core::ConstU32;
|
||||
use xcm::latest::prelude::*;
|
||||
use xcm_builder::{
|
||||
AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom,
|
||||
AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, BackingToPlurality,
|
||||
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
|
||||
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, BackingToPlurality,
|
||||
ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser,
|
||||
CurrencyAdapter as XcmCurrencyAdapter, FixedWeightBounds, IsChildSystemParachain, IsConcrete,
|
||||
LocationInverter, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation,
|
||||
TakeWeightCredit, UsingComponents, WeightInfoBounds,
|
||||
MintLocation, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation,
|
||||
TakeWeightCredit, UsingComponents, WeightInfoBounds, WithComputedOrigin,
|
||||
};
|
||||
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
|
||||
|
||||
parameter_types! {
|
||||
/// The location of the ROC token, from the context of this chain. Since this token is native to this
|
||||
/// chain, we make it synonymous with it and thus it is the `Here` location, which means "equivalent to
|
||||
/// the context".
|
||||
pub const RocLocation: MultiLocation = Here.into();
|
||||
/// The Rococo network ID. This is named.
|
||||
pub RococoNetwork: NetworkId =
|
||||
NetworkId::Named(b"Rococo".to_vec().try_into().expect("shorter than length limit; qed"));
|
||||
/// Our XCM location ancestry - i.e. what, if anything, `Parent` means evaluated in our context. Since
|
||||
/// Rococo is a top-level relay-chain, there is no ancestry.
|
||||
pub const Ancestry: MultiLocation = Here.into();
|
||||
/// The check account, which holds any native assets that have been teleported out and not back in (yet).
|
||||
pub const TokenLocation: MultiLocation = Here.into_location();
|
||||
pub const ThisNetwork: NetworkId = NetworkId::Rococo;
|
||||
pub UniversalLocation: InteriorMultiLocation = ThisNetwork::get().into();
|
||||
pub CheckAccount: AccountId = XcmPallet::check_account();
|
||||
pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local);
|
||||
}
|
||||
|
||||
/// The canonical means of converting a `MultiLocation` into an `AccountId`, used when we want to determine
|
||||
/// the sovereign account controlled by a location.
|
||||
pub type SovereignAccountOf = (
|
||||
// We can convert a child parachain using the standard `AccountId` conversion.
|
||||
ChildParachainConvertsVia<ParaId, AccountId>,
|
||||
// We can directly alias an `AccountId32` into a local account.
|
||||
AccountId32Aliases<RococoNetwork, AccountId>,
|
||||
);
|
||||
pub type LocationConverter =
|
||||
(ChildParachainConvertsVia<ParaId, AccountId>, AccountId32Aliases<ThisNetwork, AccountId>);
|
||||
|
||||
/// Our asset transactor. This is what allows us to interest with the runtime facilities from the point of
|
||||
/// view of XCM-only concepts like `MultiLocation` and `MultiAsset`.
|
||||
@@ -64,63 +57,62 @@ pub type LocalAssetTransactor = XcmCurrencyAdapter<
|
||||
// Use this currency:
|
||||
Balances,
|
||||
// Use this currency when it is a fungible asset matching the given location or name:
|
||||
IsConcrete<RocLocation>,
|
||||
IsConcrete<TokenLocation>,
|
||||
// We can convert the MultiLocations with our converter above:
|
||||
SovereignAccountOf,
|
||||
LocationConverter,
|
||||
// Our chain's account ID type (we can't get away without mentioning it explicitly):
|
||||
AccountId,
|
||||
// We track our teleports in/out to keep total issuance correct.
|
||||
CheckAccount,
|
||||
LocalCheckAccount,
|
||||
>;
|
||||
|
||||
/// The means that we convert an the XCM message origin location into a local dispatch origin.
|
||||
type LocalOriginConverter = (
|
||||
// A `Signed` origin of the sovereign account that the original location controls.
|
||||
SovereignSignedViaLocation<SovereignAccountOf, RuntimeOrigin>,
|
||||
SovereignSignedViaLocation<LocationConverter, RuntimeOrigin>,
|
||||
// A child parachain, natively expressed, has the `Parachain` origin.
|
||||
ChildParachainAsNative<parachains_origin::Origin, RuntimeOrigin>,
|
||||
// The AccountId32 location type can be expressed natively as a `Signed` origin.
|
||||
SignedAccountId32AsNative<RococoNetwork, RuntimeOrigin>,
|
||||
SignedAccountId32AsNative<ThisNetwork, RuntimeOrigin>,
|
||||
// A system child parachain, expressed as a Superuser, converts to the `Root` origin.
|
||||
ChildSystemParachainAsSuperuser<ParaId, RuntimeOrigin>,
|
||||
);
|
||||
|
||||
parameter_types! {
|
||||
/// The amount of weight an XCM operation takes. This is a safe overestimate.
|
||||
pub const BaseXcmWeight: u64 = 1_000_000_000;
|
||||
/// Maximum number of instructions in a single XCM fragment. A sanity check against weight
|
||||
/// calculations getting too crazy.
|
||||
pub const MaxInstructions: u32 = 100;
|
||||
pub const BaseXcmWeight: Weight = Weight::from_parts(1_000_000_000, 64 * 1024);
|
||||
}
|
||||
/// The XCM router. When we want to send an XCM message, we use this type. It amalgamates all of our
|
||||
/// individual routers.
|
||||
pub type XcmRouter = (
|
||||
// Only one router so far - use DMP to communicate with child parachains.
|
||||
xcm_sender::ChildParachainRouter<Runtime, XcmPallet>,
|
||||
xcm_sender::ChildParachainRouter<Runtime, XcmPallet, ()>,
|
||||
);
|
||||
|
||||
parameter_types! {
|
||||
pub const Rococo: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(RocLocation::get()) });
|
||||
pub const Statemine: MultiLocation = Parachain(1000).into();
|
||||
pub const Contracts: MultiLocation = Parachain(1002).into();
|
||||
pub const Encointer: MultiLocation = Parachain(1003).into();
|
||||
pub const Tick: MultiLocation = Parachain(100).into();
|
||||
pub const Trick: MultiLocation = Parachain(110).into();
|
||||
pub const Track: MultiLocation = Parachain(120).into();
|
||||
pub const RococoForTick: (MultiAssetFilter, MultiLocation) = (Rococo::get(), Tick::get());
|
||||
pub const RococoForTrick: (MultiAssetFilter, MultiLocation) = (Rococo::get(), Trick::get());
|
||||
pub const RococoForTrack: (MultiAssetFilter, MultiLocation) = (Rococo::get(), Track::get());
|
||||
pub const RococoForStatemine: (MultiAssetFilter, MultiLocation) = (Rococo::get(), Statemine::get());
|
||||
pub const RococoForContracts: (MultiAssetFilter, MultiLocation) = (Rococo::get(), Contracts::get());
|
||||
pub const RococoForEncointer: (MultiAssetFilter, MultiLocation) = (Rococo::get(), Encointer::get());
|
||||
pub const Roc: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) });
|
||||
pub const Statemine: MultiLocation = Parachain(1000).into_location();
|
||||
pub const Contracts: MultiLocation = Parachain(1002).into_location();
|
||||
pub const Encointer: MultiLocation = Parachain(1003).into_location();
|
||||
pub const Tick: MultiLocation = Parachain(100).into_location();
|
||||
pub const Trick: MultiLocation = Parachain(110).into_location();
|
||||
pub const Track: MultiLocation = Parachain(120).into_location();
|
||||
pub const RocForTick: (MultiAssetFilter, MultiLocation) = (Roc::get(), Tick::get());
|
||||
pub const RocForTrick: (MultiAssetFilter, MultiLocation) = (Roc::get(), Trick::get());
|
||||
pub const RocForTrack: (MultiAssetFilter, MultiLocation) = (Roc::get(), Track::get());
|
||||
pub const RocForStatemine: (MultiAssetFilter, MultiLocation) = (Roc::get(), Statemine::get());
|
||||
pub const RocForContracts: (MultiAssetFilter, MultiLocation) = (Roc::get(), Contracts::get());
|
||||
pub const RocForEncointer: (MultiAssetFilter, MultiLocation) = (Roc::get(), Encointer::get());
|
||||
pub const MaxInstructions: u32 = 100;
|
||||
pub const MaxAssetsIntoHolding: u32 = 64;
|
||||
}
|
||||
pub type TrustedTeleporters = (
|
||||
xcm_builder::Case<RococoForTick>,
|
||||
xcm_builder::Case<RococoForTrick>,
|
||||
xcm_builder::Case<RococoForTrack>,
|
||||
xcm_builder::Case<RococoForStatemine>,
|
||||
xcm_builder::Case<RococoForContracts>,
|
||||
xcm_builder::Case<RococoForEncointer>,
|
||||
xcm_builder::Case<RocForTick>,
|
||||
xcm_builder::Case<RocForTrick>,
|
||||
xcm_builder::Case<RocForTrack>,
|
||||
xcm_builder::Case<RocForStatemine>,
|
||||
xcm_builder::Case<RocForContracts>,
|
||||
xcm_builder::Case<RocForEncointer>,
|
||||
);
|
||||
|
||||
match_types! {
|
||||
@@ -133,16 +125,150 @@ match_types! {
|
||||
pub type Barrier = (
|
||||
// Weight that is paid for may be consumed.
|
||||
TakeWeightCredit,
|
||||
// If the message is one that immediately attemps to pay for execution, then allow it.
|
||||
AllowTopLevelPaidExecutionFrom<Everything>,
|
||||
// Messages coming from system parachains need not pay for execution.
|
||||
AllowUnpaidExecutionFrom<IsChildSystemParachain<ParaId>>,
|
||||
// Expected responses are OK.
|
||||
AllowKnownQueryResponses<XcmPallet>,
|
||||
// Subscriptions for version tracking are OK.
|
||||
AllowSubscriptionsFrom<OnlyParachains>,
|
||||
WithComputedOrigin<
|
||||
(
|
||||
// If the message is one that immediately attemps to pay for execution, then allow it.
|
||||
AllowTopLevelPaidExecutionFrom<Everything>,
|
||||
// Messages coming from system parachains need not pay for execution.
|
||||
AllowExplicitUnpaidExecutionFrom<IsChildSystemParachain<ParaId>>,
|
||||
// Subscriptions for version tracking are OK.
|
||||
AllowSubscriptionsFrom<OnlyParachains>,
|
||||
),
|
||||
UniversalLocation,
|
||||
ConstU32<8>,
|
||||
>,
|
||||
);
|
||||
|
||||
/// A call filter for the XCM Transact instruction. This is a temporary measure until we
|
||||
/// properly account for proof size weights.
|
||||
///
|
||||
/// Calls that are allowed through this filter must:
|
||||
/// 1. Have a fixed weight;
|
||||
/// 2. Cannot lead to another call being made;
|
||||
/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call parameters.
|
||||
pub struct SafeCallFilter;
|
||||
impl Contains<RuntimeCall> for SafeCallFilter {
|
||||
fn contains(call: &RuntimeCall) -> bool {
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
{
|
||||
if matches!(call, RuntimeCall::System(frame_system::Call::remark_with_event { .. })) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
match call {
|
||||
RuntimeCall::System(
|
||||
frame_system::Call::kill_prefix { .. } | frame_system::Call::set_heap_pages { .. },
|
||||
) |
|
||||
RuntimeCall::Babe(..) |
|
||||
RuntimeCall::Timestamp(..) |
|
||||
RuntimeCall::Indices(..) |
|
||||
RuntimeCall::Balances(..) |
|
||||
RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) |
|
||||
RuntimeCall::Grandpa(..) |
|
||||
RuntimeCall::ImOnline(..) |
|
||||
RuntimeCall::Democracy(
|
||||
pallet_democracy::Call::second { .. } |
|
||||
pallet_democracy::Call::vote { .. } |
|
||||
pallet_democracy::Call::emergency_cancel { .. } |
|
||||
pallet_democracy::Call::fast_track { .. } |
|
||||
pallet_democracy::Call::veto_external { .. } |
|
||||
pallet_democracy::Call::cancel_referendum { .. } |
|
||||
pallet_democracy::Call::delegate { .. } |
|
||||
pallet_democracy::Call::undelegate { .. } |
|
||||
pallet_democracy::Call::clear_public_proposals { .. } |
|
||||
pallet_democracy::Call::unlock { .. } |
|
||||
pallet_democracy::Call::remove_vote { .. } |
|
||||
pallet_democracy::Call::remove_other_vote { .. } |
|
||||
pallet_democracy::Call::blacklist { .. } |
|
||||
pallet_democracy::Call::cancel_proposal { .. },
|
||||
) |
|
||||
RuntimeCall::Council(
|
||||
pallet_collective::Call::vote { .. } |
|
||||
pallet_collective::Call::close_old_weight { .. } |
|
||||
pallet_collective::Call::disapprove_proposal { .. } |
|
||||
pallet_collective::Call::close { .. },
|
||||
) |
|
||||
RuntimeCall::TechnicalCommittee(
|
||||
pallet_collective::Call::vote { .. } |
|
||||
pallet_collective::Call::close_old_weight { .. } |
|
||||
pallet_collective::Call::disapprove_proposal { .. } |
|
||||
pallet_collective::Call::close { .. },
|
||||
) |
|
||||
RuntimeCall::PhragmenElection(
|
||||
pallet_elections_phragmen::Call::remove_voter { .. } |
|
||||
pallet_elections_phragmen::Call::submit_candidacy { .. } |
|
||||
pallet_elections_phragmen::Call::renounce_candidacy { .. } |
|
||||
pallet_elections_phragmen::Call::remove_member { .. } |
|
||||
pallet_elections_phragmen::Call::clean_defunct_voters { .. },
|
||||
) |
|
||||
RuntimeCall::TechnicalMembership(
|
||||
pallet_membership::Call::add_member { .. } |
|
||||
pallet_membership::Call::remove_member { .. } |
|
||||
pallet_membership::Call::swap_member { .. } |
|
||||
pallet_membership::Call::change_key { .. } |
|
||||
pallet_membership::Call::set_prime { .. } |
|
||||
pallet_membership::Call::clear_prime { .. },
|
||||
) |
|
||||
RuntimeCall::Treasury(..) |
|
||||
RuntimeCall::Claims(
|
||||
super::claims::Call::claim { .. } |
|
||||
super::claims::Call::mint_claim { .. } |
|
||||
super::claims::Call::move_claim { .. },
|
||||
) |
|
||||
RuntimeCall::Utility(pallet_utility::Call::as_derivative { .. }) |
|
||||
RuntimeCall::Identity(
|
||||
pallet_identity::Call::add_registrar { .. } |
|
||||
pallet_identity::Call::set_identity { .. } |
|
||||
pallet_identity::Call::clear_identity { .. } |
|
||||
pallet_identity::Call::request_judgement { .. } |
|
||||
pallet_identity::Call::cancel_request { .. } |
|
||||
pallet_identity::Call::set_fee { .. } |
|
||||
pallet_identity::Call::set_account_id { .. } |
|
||||
pallet_identity::Call::set_fields { .. } |
|
||||
pallet_identity::Call::provide_judgement { .. } |
|
||||
pallet_identity::Call::kill_identity { .. } |
|
||||
pallet_identity::Call::add_sub { .. } |
|
||||
pallet_identity::Call::rename_sub { .. } |
|
||||
pallet_identity::Call::remove_sub { .. } |
|
||||
pallet_identity::Call::quit_sub { .. },
|
||||
) |
|
||||
RuntimeCall::Society(
|
||||
pallet_society::Call::bid { .. } |
|
||||
pallet_society::Call::unbid { .. } |
|
||||
pallet_society::Call::vouch { .. } |
|
||||
pallet_society::Call::unvouch { .. } |
|
||||
pallet_society::Call::vote { .. } |
|
||||
pallet_society::Call::defender_vote { .. } |
|
||||
pallet_society::Call::payout { .. } |
|
||||
pallet_society::Call::unfound { .. } |
|
||||
pallet_society::Call::judge_suspended_member { .. } |
|
||||
pallet_society::Call::judge_suspended_candidate { .. } |
|
||||
pallet_society::Call::set_max_members { .. },
|
||||
) |
|
||||
RuntimeCall::Recovery(..) |
|
||||
RuntimeCall::Vesting(..) |
|
||||
RuntimeCall::Bounties(
|
||||
pallet_bounties::Call::propose_bounty { .. } |
|
||||
pallet_bounties::Call::approve_bounty { .. } |
|
||||
pallet_bounties::Call::propose_curator { .. } |
|
||||
pallet_bounties::Call::unassign_curator { .. } |
|
||||
pallet_bounties::Call::accept_curator { .. } |
|
||||
pallet_bounties::Call::award_bounty { .. } |
|
||||
pallet_bounties::Call::claim_bounty { .. } |
|
||||
pallet_bounties::Call::close_bounty { .. },
|
||||
) |
|
||||
RuntimeCall::ChildBounties(..) |
|
||||
RuntimeCall::XcmPallet(pallet_xcm::Call::limited_reserve_transfer_assets {
|
||||
..
|
||||
}) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct XcmConfig;
|
||||
impl xcm_executor::Config for XcmConfig {
|
||||
type RuntimeCall = RuntimeCall;
|
||||
@@ -151,19 +277,28 @@ impl xcm_executor::Config for XcmConfig {
|
||||
type OriginConverter = LocalOriginConverter;
|
||||
type IsReserve = ();
|
||||
type IsTeleporter = TrustedTeleporters;
|
||||
type LocationInverter = LocationInverter<Ancestry>;
|
||||
type UniversalLocation = UniversalLocation;
|
||||
type Barrier = Barrier;
|
||||
type Weigher = WeightInfoBounds<
|
||||
crate::weights::xcm::RococoXcmWeight<RuntimeCall>,
|
||||
RuntimeCall,
|
||||
MaxInstructions,
|
||||
>;
|
||||
// The weight trader piggybacks on the existing transaction-fee conversion logic.
|
||||
type Trader = UsingComponents<WeightToFee, RocLocation, AccountId, Balances, ToAuthor<Runtime>>;
|
||||
type Trader =
|
||||
UsingComponents<WeightToFee, TokenLocation, AccountId, Balances, ToAuthor<Runtime>>;
|
||||
type ResponseHandler = XcmPallet;
|
||||
type AssetTrap = XcmPallet;
|
||||
type AssetLocker = ();
|
||||
type AssetExchanger = ();
|
||||
type AssetClaims = XcmPallet;
|
||||
type SubscriptionService = XcmPallet;
|
||||
type PalletInstancesInfo = AllPalletsWithSystem;
|
||||
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
|
||||
type FeeManager = ();
|
||||
type MessageExporter = ();
|
||||
type UniversalAliases = Nothing;
|
||||
type CallDispatcher = WithOriginFilter<SafeCallFilter>;
|
||||
type SafeCallFilter = SafeCallFilter;
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
@@ -174,6 +309,11 @@ parameter_types! {
|
||||
pub const CouncilBodyId: BodyId = BodyId::Executive;
|
||||
}
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
parameter_types! {
|
||||
pub ReachableDest: Option<MultiLocation> = Some(Parachain(1000).into());
|
||||
}
|
||||
|
||||
/// Type to convert the council origin to a Plurality `MultiLocation` value.
|
||||
pub type CouncilToPlurality = BackingToPlurality<
|
||||
RuntimeOrigin,
|
||||
@@ -188,7 +328,7 @@ pub type LocalOriginToLocation = (
|
||||
// `Unit` body.
|
||||
CouncilToPlurality,
|
||||
// And a usual Signed origin to be used in XCM as a corresponding AccountId32
|
||||
SignedToAccountId32<RuntimeOrigin, AccountId, RococoNetwork>,
|
||||
SignedToAccountId32<RuntimeOrigin, AccountId, ThisNetwork>,
|
||||
);
|
||||
impl pallet_xcm::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
@@ -197,16 +337,23 @@ impl pallet_xcm::Config for Runtime {
|
||||
// Anyone can execute XCM messages locally.
|
||||
type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
|
||||
type XcmExecuteFilter = Everything;
|
||||
type XcmExecutor = xcm_executor::XcmExecutor<XcmConfig>;
|
||||
// Anyone is able to use teleportation regardless of who they are and what they want to teleport.
|
||||
type XcmExecutor = XcmExecutor<XcmConfig>;
|
||||
type XcmTeleportFilter = Everything;
|
||||
// Anyone is able to use reserve transfers regardless of who they are and what they want to
|
||||
// transfer.
|
||||
type XcmReserveTransferFilter = Everything;
|
||||
type Weigher = FixedWeightBounds<BaseXcmWeight, RuntimeCall, MaxInstructions>;
|
||||
type LocationInverter = LocationInverter<Ancestry>;
|
||||
type UniversalLocation = UniversalLocation;
|
||||
type RuntimeOrigin = RuntimeOrigin;
|
||||
type RuntimeCall = RuntimeCall;
|
||||
const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
|
||||
type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
|
||||
type Currency = Balances;
|
||||
type CurrencyMatcher = IsConcrete<TokenLocation>;
|
||||
type TrustedLockers = ();
|
||||
type SovereignAccountOf = LocationConverter;
|
||||
type MaxLockers = ConstU32<8>;
|
||||
type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type ReachableDest = ReachableDest;
|
||||
}
|
||||
|
||||
@@ -129,3 +129,7 @@ std = [
|
||||
"frame-election-provider-support/std",
|
||||
"pallet-sudo/std",
|
||||
]
|
||||
|
||||
runtime-benchmarks = [
|
||||
"pallet-xcm/runtime-benchmarks",
|
||||
]
|
||||
|
||||
@@ -131,7 +131,7 @@ parameter_types! {
|
||||
}
|
||||
|
||||
impl frame_system::Config for Runtime {
|
||||
type BaseCallFilter = frame_support::traits::Everything;
|
||||
type BaseCallFilter = Everything;
|
||||
type BlockWeights = BlockWeights;
|
||||
type BlockLength = BlockLength;
|
||||
type DbWeight = ();
|
||||
@@ -537,34 +537,6 @@ impl parachains_ump::Config for Runtime {
|
||||
type WeightInfo = parachains_ump::TestWeightInfo;
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const BaseXcmWeight: xcm::latest::Weight = 1_000;
|
||||
pub const AnyNetwork: xcm::latest::NetworkId = xcm::latest::NetworkId::Any;
|
||||
pub const MaxInstructions: u32 = 100;
|
||||
}
|
||||
|
||||
pub type LocalOriginToLocation =
|
||||
xcm_builder::SignedToAccountId32<RuntimeOrigin, AccountId, AnyNetwork>;
|
||||
|
||||
impl pallet_xcm::Config for Runtime {
|
||||
// The config types here are entirely configurable, since the only one that is sorely needed
|
||||
// is `XcmExecutor`, which will be used in unit tests located in xcm-executor.
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
|
||||
type LocationInverter = xcm_config::InvertNothing;
|
||||
type SendXcmOrigin = xcm_builder::EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
|
||||
type Weigher = xcm_builder::FixedWeightBounds<BaseXcmWeight, RuntimeCall, MaxInstructions>;
|
||||
type XcmRouter = xcm_config::DoNothingRouter;
|
||||
type XcmExecuteFilter = Everything;
|
||||
type XcmExecutor = xcm_executor::XcmExecutor<xcm_config::XcmConfig>;
|
||||
type XcmTeleportFilter = Everything;
|
||||
type XcmReserveTransferFilter = Everything;
|
||||
type RuntimeOrigin = RuntimeOrigin;
|
||||
type RuntimeCall = RuntimeCall;
|
||||
const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
|
||||
type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
|
||||
}
|
||||
|
||||
impl parachains_hrmp::Config for Runtime {
|
||||
type RuntimeOrigin = RuntimeOrigin;
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
@@ -628,8 +600,9 @@ pub mod pallet_test_notifier {
|
||||
.using_encoded(|mut d| <[u8; 32]>::decode(&mut d))
|
||||
.map_err(|_| Error::<T>::BadAccountFormat)?;
|
||||
let qid = pallet_xcm::Pallet::<T>::new_query(
|
||||
Junction::AccountId32 { network: Any, id }.into(),
|
||||
Junction::AccountId32 { network: None, id },
|
||||
100u32.into(),
|
||||
Here,
|
||||
);
|
||||
Self::deposit_event(Event::<T>::QueryPrepared(qid));
|
||||
Ok(())
|
||||
@@ -645,9 +618,10 @@ pub mod pallet_test_notifier {
|
||||
let call =
|
||||
Call::<T>::notification_received { query_id: 0, response: Default::default() };
|
||||
let qid = pallet_xcm::Pallet::<T>::new_notify_query(
|
||||
Junction::AccountId32 { network: Any, id }.into(),
|
||||
Junction::AccountId32 { network: None, id },
|
||||
<T as Config>::RuntimeCall::from(call),
|
||||
100u32.into(),
|
||||
Here,
|
||||
);
|
||||
Self::deposit_event(Event::<T>::NotifyQueryPrepared(qid));
|
||||
Ok(())
|
||||
|
||||
@@ -14,30 +14,44 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use frame_support::{parameter_types, traits::Everything};
|
||||
use xcm::latest::{prelude::*, Weight as XCMWeight};
|
||||
use xcm_builder::{AllowUnpaidExecutionFrom, FixedWeightBounds, SignedToAccountId32};
|
||||
use frame_support::{
|
||||
parameter_types,
|
||||
traits::{Everything, Nothing},
|
||||
weights::Weight,
|
||||
};
|
||||
use xcm::latest::prelude::*;
|
||||
use xcm_builder::{
|
||||
AllowUnpaidExecutionFrom, EnsureXcmOrigin, FixedWeightBounds, SignedAccountId32AsNative,
|
||||
SignedToAccountId32,
|
||||
};
|
||||
use xcm_executor::{
|
||||
traits::{InvertLocation, TransactAsset, WeightTrader},
|
||||
traits::{TransactAsset, WeightTrader},
|
||||
Assets,
|
||||
};
|
||||
|
||||
parameter_types! {
|
||||
pub const OurNetwork: NetworkId = NetworkId::Polkadot;
|
||||
pub const BaseXcmWeight: xcm::latest::Weight = Weight::from_parts(1_000, 1_000);
|
||||
pub const AnyNetwork: Option<NetworkId> = None;
|
||||
pub const MaxInstructions: u32 = 100;
|
||||
pub const MaxAssetsIntoHolding: u32 = 16;
|
||||
pub const UniversalLocation: xcm::latest::InteriorMultiLocation = xcm::latest::Junctions::Here;
|
||||
}
|
||||
|
||||
/// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior location
|
||||
/// of this chain.
|
||||
pub type LocalOriginToLocation = (
|
||||
// And a usual Signed origin to be used in XCM as a corresponding AccountId32
|
||||
SignedToAccountId32<crate::RuntimeOrigin, crate::AccountId, OurNetwork>,
|
||||
SignedToAccountId32<crate::RuntimeOrigin, crate::AccountId, AnyNetwork>,
|
||||
);
|
||||
|
||||
pub struct DoNothingRouter;
|
||||
impl SendXcm for DoNothingRouter {
|
||||
fn send_xcm(_dest: impl Into<MultiLocation>, _msg: Xcm<()>) -> SendResult {
|
||||
Ok(())
|
||||
type Ticket = ();
|
||||
fn validate(_dest: &mut Option<MultiLocation>, _msg: &mut Option<Xcm<()>>) -> SendResult<()> {
|
||||
Ok(((), MultiAssets::new()))
|
||||
}
|
||||
fn deliver(_: ()) -> Result<XcmHash, SendError> {
|
||||
Ok([0; 32])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,11 +59,15 @@ pub type Barrier = AllowUnpaidExecutionFrom<Everything>;
|
||||
|
||||
pub struct DummyAssetTransactor;
|
||||
impl TransactAsset for DummyAssetTransactor {
|
||||
fn deposit_asset(_what: &MultiAsset, _who: &MultiLocation) -> XcmResult {
|
||||
fn deposit_asset(_what: &MultiAsset, _who: &MultiLocation, _context: &XcmContext) -> XcmResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn withdraw_asset(_what: &MultiAsset, _who: &MultiLocation) -> Result<Assets, XcmError> {
|
||||
fn withdraw_asset(
|
||||
_what: &MultiAsset,
|
||||
_who: &MultiLocation,
|
||||
_maybe_context: Option<&XcmContext>,
|
||||
) -> Result<Assets, XcmError> {
|
||||
let asset: MultiAsset = (Parent, 100_000).into();
|
||||
Ok(asset.into())
|
||||
}
|
||||
@@ -61,35 +79,71 @@ impl WeightTrader for DummyWeightTrader {
|
||||
DummyWeightTrader
|
||||
}
|
||||
|
||||
fn buy_weight(&mut self, _weight: XCMWeight, _payment: Assets) -> Result<Assets, XcmError> {
|
||||
fn buy_weight(&mut self, _weight: Weight, _payment: Assets) -> Result<Assets, XcmError> {
|
||||
Ok(Assets::default())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct InvertNothing;
|
||||
impl InvertLocation for InvertNothing {
|
||||
fn invert_location(_: &MultiLocation) -> sp_std::result::Result<MultiLocation, ()> {
|
||||
Ok(Here.into())
|
||||
}
|
||||
fn ancestry() -> MultiLocation {
|
||||
Here.into()
|
||||
}
|
||||
}
|
||||
type OriginConverter = (
|
||||
pallet_xcm::XcmPassthrough<super::RuntimeOrigin>,
|
||||
SignedAccountId32AsNative<AnyNetwork, super::RuntimeOrigin>,
|
||||
);
|
||||
|
||||
pub struct XcmConfig;
|
||||
impl xcm_executor::Config for XcmConfig {
|
||||
type RuntimeCall = super::RuntimeCall;
|
||||
type XcmSender = DoNothingRouter;
|
||||
type AssetTransactor = DummyAssetTransactor;
|
||||
type OriginConverter = pallet_xcm::XcmPassthrough<super::RuntimeOrigin>;
|
||||
type OriginConverter = OriginConverter;
|
||||
type IsReserve = ();
|
||||
type IsTeleporter = ();
|
||||
type LocationInverter = InvertNothing;
|
||||
type UniversalLocation = UniversalLocation;
|
||||
type Barrier = Barrier;
|
||||
type Weigher = FixedWeightBounds<super::BaseXcmWeight, super::RuntimeCall, MaxInstructions>;
|
||||
type Weigher = FixedWeightBounds<BaseXcmWeight, super::RuntimeCall, MaxInstructions>;
|
||||
type Trader = DummyWeightTrader;
|
||||
type ResponseHandler = super::Xcm;
|
||||
type AssetTrap = super::Xcm;
|
||||
type AssetLocker = ();
|
||||
type AssetExchanger = ();
|
||||
type AssetClaims = super::Xcm;
|
||||
type SubscriptionService = super::Xcm;
|
||||
type PalletInstancesInfo = ();
|
||||
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
|
||||
type FeeManager = ();
|
||||
type MessageExporter = ();
|
||||
type UniversalAliases = Nothing;
|
||||
type CallDispatcher = super::RuntimeCall;
|
||||
type SafeCallFilter = Everything;
|
||||
}
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
parameter_types! {
|
||||
pub ReachableDest: Option<MultiLocation> = Some(xcm::latest::Junctions::Here.into());
|
||||
}
|
||||
|
||||
impl pallet_xcm::Config for crate::Runtime {
|
||||
// The config types here are entirely configurable, since the only one that is sorely needed
|
||||
// is `XcmExecutor`, which will be used in unit tests located in xcm-executor.
|
||||
type RuntimeEvent = crate::RuntimeEvent;
|
||||
type ExecuteXcmOrigin = EnsureXcmOrigin<crate::RuntimeOrigin, LocalOriginToLocation>;
|
||||
type UniversalLocation = UniversalLocation;
|
||||
type SendXcmOrigin = EnsureXcmOrigin<crate::RuntimeOrigin, LocalOriginToLocation>;
|
||||
type Weigher = FixedWeightBounds<BaseXcmWeight, crate::RuntimeCall, MaxInstructions>;
|
||||
type XcmRouter = DoNothingRouter;
|
||||
type XcmExecuteFilter = Everything;
|
||||
type XcmExecutor = xcm_executor::XcmExecutor<XcmConfig>;
|
||||
type XcmTeleportFilter = Everything;
|
||||
type XcmReserveTransferFilter = Everything;
|
||||
type RuntimeOrigin = crate::RuntimeOrigin;
|
||||
type RuntimeCall = crate::RuntimeCall;
|
||||
const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
|
||||
type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
|
||||
type Currency = crate::Balances;
|
||||
type CurrencyMatcher = ();
|
||||
type TrustedLockers = ();
|
||||
type SovereignAccountOf = ();
|
||||
type MaxLockers = frame_support::traits::ConstU32<8>;
|
||||
type WeightInfo = pallet_xcm::TestWeightInfo;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type ReachableDest = ReachableDest;
|
||||
}
|
||||
|
||||
@@ -1247,6 +1247,9 @@ pub type Migrations = (
|
||||
parachains_disputes::migration::v1::MigrateToV1<Runtime>,
|
||||
parachains_configuration::migration::v4::MigrateToV4<Runtime>,
|
||||
init_state_migration::InitMigrate,
|
||||
// "Use 2D weights in XCM v3" <https://github.com/paritytech/polkadot/pull/6134>
|
||||
pallet_xcm::migration::v1::MigrateToV1<Runtime>,
|
||||
parachains_ump::migration::v1::MigrateToV1<Runtime>,
|
||||
);
|
||||
|
||||
/// Unchecked extrinsic type as expected by this runtime.
|
||||
@@ -1309,6 +1312,7 @@ mod benches {
|
||||
[pallet_utility, Utility]
|
||||
[pallet_vesting, Vesting]
|
||||
// XCM
|
||||
[pallet_xcm, XcmPallet]
|
||||
// NOTE: Make sure you point to the individual modules below.
|
||||
[pallet_xcm_benchmarks::fungible, XcmBalances]
|
||||
[pallet_xcm_benchmarks::generic, XcmGeneric]
|
||||
@@ -1728,10 +1732,10 @@ sp_api::impl_runtime_apis! {
|
||||
impl runtime_parachains::disputes::slashing::benchmarking::Config for Runtime {}
|
||||
|
||||
use xcm::latest::{
|
||||
AssetId::*, Fungibility::*, Junctions::*, MultiAsset, MultiAssets, MultiLocation,
|
||||
Response,
|
||||
AssetId::*, Fungibility::*, Junction, Junctions::*, MultiAsset, MultiAssets,
|
||||
MultiLocation, Response,
|
||||
};
|
||||
use xcm_config::{Westmint, WndLocation};
|
||||
use xcm_config::{Westmint, TokenLocation};
|
||||
|
||||
impl pallet_xcm_benchmarks::Config for Runtime {
|
||||
type XcmConfig = xcm_config::XcmConfig;
|
||||
@@ -1739,10 +1743,10 @@ sp_api::impl_runtime_apis! {
|
||||
fn valid_destination() -> Result<MultiLocation, BenchmarkError> {
|
||||
Ok(Westmint::get())
|
||||
}
|
||||
fn worst_case_holding() -> MultiAssets {
|
||||
fn worst_case_holding(_depositable_count: u32) -> MultiAssets {
|
||||
// Westend only knows about WND.
|
||||
vec![MultiAsset{
|
||||
id: Concrete(WndLocation::get()),
|
||||
id: Concrete(TokenLocation::get()),
|
||||
fun: Fungible(1_000_000 * UNITS),
|
||||
}].into()
|
||||
}
|
||||
@@ -1751,24 +1755,19 @@ sp_api::impl_runtime_apis! {
|
||||
parameter_types! {
|
||||
pub const TrustedTeleporter: Option<(MultiLocation, MultiAsset)> = Some((
|
||||
Westmint::get(),
|
||||
MultiAsset { fun: Fungible(1 * UNITS), id: Concrete(WndLocation::get()) },
|
||||
));
|
||||
pub const TrustedReserve: Option<(MultiLocation, MultiAsset)> = Some((
|
||||
Westmint::get(),
|
||||
MultiAsset { fun: Fungible(1 * UNITS), id: Concrete(WndLocation::get()) },
|
||||
MultiAsset { fun: Fungible(1 * UNITS), id: Concrete(TokenLocation::get()) },
|
||||
));
|
||||
}
|
||||
|
||||
impl pallet_xcm_benchmarks::fungible::Config for Runtime {
|
||||
type TransactAsset = Balances;
|
||||
|
||||
type CheckedAccount = xcm_config::CheckAccount;
|
||||
type CheckedAccount = xcm_config::LocalCheckAccount;
|
||||
type TrustedTeleporter = TrustedTeleporter;
|
||||
type TrustedReserve = TrustedReserve;
|
||||
|
||||
fn get_multi_asset() -> MultiAsset {
|
||||
MultiAsset {
|
||||
id: Concrete(WndLocation::get()),
|
||||
id: Concrete(TokenLocation::get()),
|
||||
fun: Fungible(1 * UNITS),
|
||||
}
|
||||
}
|
||||
@@ -1781,8 +1780,18 @@ sp_api::impl_runtime_apis! {
|
||||
(0u64, Response::Version(Default::default()))
|
||||
}
|
||||
|
||||
fn transact_origin() -> Result<MultiLocation, BenchmarkError> {
|
||||
Ok(Westmint::get())
|
||||
fn worst_case_asset_exchange() -> Result<(MultiAssets, MultiAssets), BenchmarkError> {
|
||||
// Westend doesn't support asset exchanges
|
||||
Err(BenchmarkError::Skip)
|
||||
}
|
||||
|
||||
fn universal_alias() -> Result<Junction, BenchmarkError> {
|
||||
// The XCM executor of Westend doesn't have a configured `UniversalAliases`
|
||||
Err(BenchmarkError::Skip)
|
||||
}
|
||||
|
||||
fn transact_origin_and_runtime_call() -> Result<(MultiLocation, RuntimeCall), BenchmarkError> {
|
||||
Ok((Westmint::get(), frame_system::Call::remark_with_event { remark: vec![] }.into()))
|
||||
}
|
||||
|
||||
fn subscribe_origin() -> Result<MultiLocation, BenchmarkError> {
|
||||
@@ -1791,10 +1800,15 @@ sp_api::impl_runtime_apis! {
|
||||
|
||||
fn claimable_asset() -> Result<(MultiLocation, MultiLocation, MultiAssets), BenchmarkError> {
|
||||
let origin = Westmint::get();
|
||||
let assets: MultiAssets = (Concrete(WndLocation::get()), 1_000 * UNITS).into();
|
||||
let assets: MultiAssets = (Concrete(TokenLocation::get()), 1_000 * UNITS).into();
|
||||
let ticket = MultiLocation { parents: 0, interior: Here };
|
||||
Ok((origin, ticket, assets))
|
||||
}
|
||||
|
||||
fn unlockable_asset() -> Result<(MultiLocation, MultiLocation, MultiAsset), BenchmarkError> {
|
||||
// Westend doesn't support asset locking
|
||||
Err(BenchmarkError::Skip)
|
||||
}
|
||||
}
|
||||
|
||||
type XcmBalances = pallet_xcm_benchmarks::fungible::Pallet::<Runtime>;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
//! Tests for the Westend Runtime Configuration
|
||||
|
||||
use crate::*;
|
||||
use xcm::latest::{AssetId::*, Fungibility::*, MultiLocation};
|
||||
use xcm::latest::prelude::*;
|
||||
|
||||
#[test]
|
||||
fn remove_keys_weight_is_sensible() {
|
||||
@@ -57,9 +57,9 @@ fn sanity_check_teleport_assets_weight() {
|
||||
// so this test will certainly ensure that this problem does not occur.
|
||||
use frame_support::dispatch::GetDispatchInfo;
|
||||
let weight = pallet_xcm::Call::<Runtime>::teleport_assets {
|
||||
dest: Box::new(xcm::VersionedMultiLocation::V1(MultiLocation::here())),
|
||||
beneficiary: Box::new(xcm::VersionedMultiLocation::V1(MultiLocation::here())),
|
||||
assets: Box::new((Concrete(MultiLocation::here()), Fungible(200_000)).into()),
|
||||
dest: Box::new(Here.into()),
|
||||
beneficiary: Box::new(Here.into()),
|
||||
assets: Box::new((Here, 200_000).into()),
|
||||
fee_asset_item: 0,
|
||||
}
|
||||
.get_dispatch_info()
|
||||
|
||||
@@ -34,6 +34,7 @@ pub mod pallet_staking;
|
||||
pub mod pallet_timestamp;
|
||||
pub mod pallet_utility;
|
||||
pub mod pallet_vesting;
|
||||
pub mod pallet_xcm;
|
||||
pub mod runtime_common_auctions;
|
||||
pub mod runtime_common_crowdloan;
|
||||
pub mod runtime_common_paras_registrar;
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
// Copyright 2017-2022 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/>.
|
||||
//! Autogenerated weights for `pallet_xcm`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2022-12-16, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024
|
||||
|
||||
// Executed Command:
|
||||
// /home/benchbot/cargo_target_dir/production/polkadot
|
||||
// benchmark
|
||||
// pallet
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
// --extrinsic=*
|
||||
// --execution=wasm
|
||||
// --wasm-execution=compiled
|
||||
// --heap-pages=4096
|
||||
// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/polkadot/.git/.artifacts/bench.json
|
||||
// --pallet=pallet_xcm
|
||||
// --chain=westend-dev
|
||||
// --header=./file_header.txt
|
||||
// --output=./runtime/westend/src/weights/
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use frame_support::{traits::Get, weights::Weight};
|
||||
use sp_std::marker::PhantomData;
|
||||
|
||||
/// Weight functions for `pallet_xcm`.
|
||||
pub struct WeightInfo<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
fn send() -> Weight {
|
||||
// Minimum execution time: 36_453 nanoseconds.
|
||||
Weight::from_ref_time(37_511_000)
|
||||
.saturating_add(T::DbWeight::get().reads(5))
|
||||
.saturating_add(T::DbWeight::get().writes(3))
|
||||
}
|
||||
fn teleport_assets() -> Weight {
|
||||
// Minimum execution time: 28_144 nanoseconds.
|
||||
Weight::from_ref_time(28_952_000)
|
||||
}
|
||||
fn reserve_transfer_assets() -> Weight {
|
||||
// Minimum execution time: 28_245 nanoseconds.
|
||||
Weight::from_ref_time(28_710_000)
|
||||
}
|
||||
// Storage: Benchmark Override (r:0 w:0)
|
||||
fn execute() -> Weight {
|
||||
// Minimum execution time: 18_446_744_073_709_551 nanoseconds.
|
||||
Weight::from_ref_time(18_446_744_073_709_551_000)
|
||||
}
|
||||
// Storage: XcmPallet SupportedVersion (r:0 w:1)
|
||||
fn force_xcm_version() -> Weight {
|
||||
// Minimum execution time: 15_350 nanoseconds.
|
||||
Weight::from_ref_time(15_829_000)
|
||||
.saturating_add(T::DbWeight::get().writes(1))
|
||||
}
|
||||
// Storage: XcmPallet SafeXcmVersion (r:0 w:1)
|
||||
fn force_default_xcm_version() -> Weight {
|
||||
// Minimum execution time: 4_482 nanoseconds.
|
||||
Weight::from_ref_time(4_588_000)
|
||||
.saturating_add(T::DbWeight::get().writes(1))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifiers (r:1 w:1)
|
||||
// Storage: XcmPallet QueryCounter (r:1 w:1)
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
// Storage: XcmPallet Queries (r:0 w:1)
|
||||
fn force_subscribe_version_notify() -> Weight {
|
||||
// Minimum execution time: 41_818 nanoseconds.
|
||||
Weight::from_ref_time(42_824_000)
|
||||
.saturating_add(T::DbWeight::get().reads(7))
|
||||
.saturating_add(T::DbWeight::get().writes(6))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifiers (r:1 w:1)
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
// Storage: XcmPallet Queries (r:0 w:1)
|
||||
fn force_unsubscribe_version_notify() -> Weight {
|
||||
// Minimum execution time: 45_488 nanoseconds.
|
||||
Weight::from_ref_time(46_295_000)
|
||||
.saturating_add(T::DbWeight::get().reads(6))
|
||||
.saturating_add(T::DbWeight::get().writes(5))
|
||||
}
|
||||
// Storage: XcmPallet SupportedVersion (r:4 w:2)
|
||||
fn migrate_supported_version() -> Weight {
|
||||
// Minimum execution time: 14_614 nanoseconds.
|
||||
Weight::from_ref_time(14_829_000)
|
||||
.saturating_add(T::DbWeight::get().reads(4))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifiers (r:4 w:2)
|
||||
fn migrate_version_notifiers() -> Weight {
|
||||
// Minimum execution time: 14_724 nanoseconds.
|
||||
Weight::from_ref_time(14_915_000)
|
||||
.saturating_add(T::DbWeight::get().reads(4))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifyTargets (r:5 w:0)
|
||||
fn already_notified_target() -> Weight {
|
||||
// Minimum execution time: 16_814 nanoseconds.
|
||||
Weight::from_ref_time(17_007_000)
|
||||
.saturating_add(T::DbWeight::get().reads(5))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifyTargets (r:2 w:1)
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
fn notify_current_targets() -> Weight {
|
||||
// Minimum execution time: 37_273 nanoseconds.
|
||||
Weight::from_ref_time(37_869_000)
|
||||
.saturating_add(T::DbWeight::get().reads(7))
|
||||
.saturating_add(T::DbWeight::get().writes(4))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifyTargets (r:3 w:0)
|
||||
fn notify_target_migration_fail() -> Weight {
|
||||
// Minimum execution time: 7_517 nanoseconds.
|
||||
Weight::from_ref_time(7_682_000)
|
||||
.saturating_add(T::DbWeight::get().reads(3))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifyTargets (r:4 w:2)
|
||||
fn migrate_version_notify_targets() -> Weight {
|
||||
// Minimum execution time: 15_088 nanoseconds.
|
||||
Weight::from_ref_time(15_464_000)
|
||||
.saturating_add(T::DbWeight::get().reads(4))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifyTargets (r:4 w:2)
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
fn migrate_and_notify_old_targets() -> Weight {
|
||||
// Minimum execution time: 42_829 nanoseconds.
|
||||
Weight::from_ref_time(43_814_000)
|
||||
.saturating_add(T::DbWeight::get().reads(9))
|
||||
.saturating_add(T::DbWeight::get().writes(5))
|
||||
}
|
||||
}
|
||||
@@ -16,23 +16,25 @@
|
||||
//! Autogenerated weights for `runtime_parachains::ump`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2022-11-16, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
|
||||
//! DATE: 2023-01-16, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024
|
||||
|
||||
// Executed Command:
|
||||
// ./target/production/polkadot
|
||||
// /home/benchbot/cargo_target_dir/production/polkadot
|
||||
// benchmark
|
||||
// pallet
|
||||
// --chain=westend-dev
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
// --pallet=runtime_parachains::ump
|
||||
// --extrinsic=*
|
||||
// --execution=wasm
|
||||
// --wasm-execution=compiled
|
||||
// --heap-pages=4096
|
||||
// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/polkadot/.git/.artifacts/bench.json
|
||||
// --pallet=runtime_parachains::ump
|
||||
// --chain=westend-dev
|
||||
// --header=./file_header.txt
|
||||
// --output=./runtime/westend/src/weights/runtime_parachains_ump.rs
|
||||
// --output=./runtime/westend/src/weights/
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
@@ -46,26 +48,27 @@ pub struct WeightInfo<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> runtime_parachains::ump::WeightInfo for WeightInfo<T> {
|
||||
/// The range of component `s` is `[0, 51200]`.
|
||||
fn process_upward_message(s: u32, ) -> Weight {
|
||||
// Minimum execution time: 10_921 nanoseconds.
|
||||
Weight::from_ref_time(5_417_303 as u64)
|
||||
// Standard Error: 13
|
||||
.saturating_add(Weight::from_ref_time(1_939 as u64).saturating_mul(s as u64))
|
||||
// Minimum execution time: 10_155 nanoseconds.
|
||||
Weight::from_ref_time(4_325_532)
|
||||
// Standard Error: 11
|
||||
.saturating_add(Weight::from_ref_time(1_926).saturating_mul(s.into()))
|
||||
}
|
||||
// Storage: Ump NeedsDispatch (r:1 w:1)
|
||||
// Storage: Ump NextDispatchRoundStartWith (r:1 w:1)
|
||||
// Storage: Ump RelayDispatchQueues (r:0 w:1)
|
||||
// Storage: Ump RelayDispatchQueueSize (r:0 w:1)
|
||||
fn clean_ump_after_outgoing() -> Weight {
|
||||
// Minimum execution time: 9_499 nanoseconds.
|
||||
Weight::from_ref_time(9_800_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(2 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(4 as u64))
|
||||
// Minimum execution time: 9_674 nanoseconds.
|
||||
Weight::from_ref_time(9_964_000)
|
||||
.saturating_add(T::DbWeight::get().reads(2))
|
||||
.saturating_add(T::DbWeight::get().writes(4))
|
||||
}
|
||||
// Storage: Ump Overweight (r:1 w:1)
|
||||
// Storage: Ump CounterForOverweight (r:1 w:1)
|
||||
fn service_overweight() -> Weight {
|
||||
// Minimum execution time: 26_656 nanoseconds.
|
||||
Weight::from_ref_time(27_122_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(1 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as u64))
|
||||
// Minimum execution time: 29_605 nanoseconds.
|
||||
Weight::from_ref_time(30_173_000)
|
||||
.saturating_add(T::DbWeight::get().reads(2))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::Runtime;
|
||||
use frame_support::weights::Weight;
|
||||
use sp_std::prelude::*;
|
||||
use xcm::{
|
||||
latest::{prelude::*, Weight as XCMWeight},
|
||||
latest::{prelude::*, QueryResponseInfo},
|
||||
DoubleEncoded,
|
||||
};
|
||||
|
||||
@@ -31,15 +31,15 @@ impl From<&MultiAsset> for AssetTypes {
|
||||
}
|
||||
|
||||
trait WeighMultiAssets {
|
||||
fn weigh_multi_assets(&self, balances_weight: Weight) -> XCMWeight;
|
||||
fn weigh_multi_assets(&self, balances_weight: Weight) -> Weight;
|
||||
}
|
||||
|
||||
// Westend only knows about one asset, the balances pallet.
|
||||
const MAX_ASSETS: u32 = 1;
|
||||
|
||||
impl WeighMultiAssets for MultiAssetFilter {
|
||||
fn weigh_multi_assets(&self, balances_weight: Weight) -> XCMWeight {
|
||||
let weight = match self {
|
||||
fn weigh_multi_assets(&self, balances_weight: Weight) -> Weight {
|
||||
match self {
|
||||
Self::Definite(assets) => assets
|
||||
.inner()
|
||||
.into_iter()
|
||||
@@ -49,155 +49,214 @@ impl WeighMultiAssets for MultiAssetFilter {
|
||||
AssetTypes::Unknown => Weight::MAX,
|
||||
})
|
||||
.fold(Weight::zero(), |acc, x| acc.saturating_add(x)),
|
||||
Self::Wild(_) => balances_weight.saturating_mul(MAX_ASSETS as u64),
|
||||
};
|
||||
|
||||
weight.ref_time()
|
||||
Self::Wild(AllOf { .. } | AllOfCounted { .. }) => balances_weight,
|
||||
Self::Wild(AllCounted(count)) => balances_weight.saturating_mul(*count as u64),
|
||||
Self::Wild(All) => balances_weight.saturating_mul(MAX_ASSETS as u64),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WeighMultiAssets for MultiAssets {
|
||||
fn weigh_multi_assets(&self, balances_weight: Weight) -> XCMWeight {
|
||||
let weight = self
|
||||
.inner()
|
||||
fn weigh_multi_assets(&self, balances_weight: Weight) -> Weight {
|
||||
self.inner()
|
||||
.into_iter()
|
||||
.map(|m| <AssetTypes as From<&MultiAsset>>::from(m))
|
||||
.map(|t| match t {
|
||||
AssetTypes::Balances => balances_weight,
|
||||
AssetTypes::Unknown => Weight::MAX,
|
||||
})
|
||||
.fold(Weight::zero(), |acc, x| acc.saturating_add(x));
|
||||
|
||||
weight.ref_time()
|
||||
.fold(Weight::zero(), |acc, x| acc.saturating_add(x))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WestendXcmWeight<RuntimeCall>(core::marker::PhantomData<RuntimeCall>);
|
||||
impl<RuntimeCall> XcmWeightInfo<RuntimeCall> for WestendXcmWeight<RuntimeCall> {
|
||||
fn withdraw_asset(assets: &MultiAssets) -> XCMWeight {
|
||||
fn withdraw_asset(assets: &MultiAssets) -> Weight {
|
||||
assets.weigh_multi_assets(XcmBalancesWeight::<Runtime>::withdraw_asset())
|
||||
}
|
||||
fn reserve_asset_deposited(assets: &MultiAssets) -> XCMWeight {
|
||||
fn reserve_asset_deposited(assets: &MultiAssets) -> Weight {
|
||||
assets.weigh_multi_assets(XcmBalancesWeight::<Runtime>::reserve_asset_deposited())
|
||||
}
|
||||
fn receive_teleported_asset(assets: &MultiAssets) -> XCMWeight {
|
||||
fn receive_teleported_asset(assets: &MultiAssets) -> Weight {
|
||||
assets.weigh_multi_assets(XcmBalancesWeight::<Runtime>::receive_teleported_asset())
|
||||
}
|
||||
fn query_response(_query_id: &u64, _response: &Response, _max_weight: &u64) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::query_response().ref_time()
|
||||
fn query_response(
|
||||
_query_id: &u64,
|
||||
_response: &Response,
|
||||
_max_weight: &Weight,
|
||||
_querier: &Option<MultiLocation>,
|
||||
) -> Weight {
|
||||
XcmGeneric::<Runtime>::query_response()
|
||||
}
|
||||
fn transfer_asset(assets: &MultiAssets, _dest: &MultiLocation) -> XCMWeight {
|
||||
fn transfer_asset(assets: &MultiAssets, _dest: &MultiLocation) -> Weight {
|
||||
assets.weigh_multi_assets(XcmBalancesWeight::<Runtime>::transfer_asset())
|
||||
}
|
||||
fn transfer_reserve_asset(
|
||||
assets: &MultiAssets,
|
||||
_dest: &MultiLocation,
|
||||
_xcm: &Xcm<()>,
|
||||
) -> XCMWeight {
|
||||
) -> Weight {
|
||||
assets.weigh_multi_assets(XcmBalancesWeight::<Runtime>::transfer_reserve_asset())
|
||||
}
|
||||
fn transact(
|
||||
_origin_type: &OriginKind,
|
||||
_require_weight_at_most: &u64,
|
||||
_origin_kind: &OriginKind,
|
||||
_require_weight_at_most: &Weight,
|
||||
_call: &DoubleEncoded<RuntimeCall>,
|
||||
) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::transact().ref_time()
|
||||
) -> Weight {
|
||||
XcmGeneric::<Runtime>::transact()
|
||||
}
|
||||
fn hrmp_new_channel_open_request(
|
||||
_sender: &u32,
|
||||
_max_message_size: &u32,
|
||||
_max_capacity: &u32,
|
||||
) -> XCMWeight {
|
||||
) -> Weight {
|
||||
// XCM Executor does not currently support HRMP channel operations
|
||||
Weight::MAX.ref_time()
|
||||
Weight::MAX
|
||||
}
|
||||
fn hrmp_channel_accepted(_recipient: &u32) -> XCMWeight {
|
||||
fn hrmp_channel_accepted(_recipient: &u32) -> Weight {
|
||||
// XCM Executor does not currently support HRMP channel operations
|
||||
Weight::MAX.ref_time()
|
||||
Weight::MAX
|
||||
}
|
||||
fn hrmp_channel_closing(_initiator: &u32, _sender: &u32, _recipient: &u32) -> XCMWeight {
|
||||
fn hrmp_channel_closing(_initiator: &u32, _sender: &u32, _recipient: &u32) -> Weight {
|
||||
// XCM Executor does not currently support HRMP channel operations
|
||||
Weight::MAX.ref_time()
|
||||
Weight::MAX
|
||||
}
|
||||
fn clear_origin() -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::clear_origin().ref_time()
|
||||
fn clear_origin() -> Weight {
|
||||
XcmGeneric::<Runtime>::clear_origin()
|
||||
}
|
||||
fn descend_origin(_who: &InteriorMultiLocation) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::descend_origin().ref_time()
|
||||
fn descend_origin(_who: &InteriorMultiLocation) -> Weight {
|
||||
XcmGeneric::<Runtime>::descend_origin()
|
||||
}
|
||||
fn report_error(
|
||||
_query_id: &QueryId,
|
||||
_dest: &MultiLocation,
|
||||
_max_response_weight: &u64,
|
||||
) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::report_error().ref_time()
|
||||
fn report_error(_query_repsonse_info: &QueryResponseInfo) -> Weight {
|
||||
XcmGeneric::<Runtime>::report_error()
|
||||
}
|
||||
|
||||
fn deposit_asset(
|
||||
assets: &MultiAssetFilter,
|
||||
_max_assets: &u32, // TODO use max assets?
|
||||
_dest: &MultiLocation,
|
||||
) -> XCMWeight {
|
||||
fn deposit_asset(assets: &MultiAssetFilter, _dest: &MultiLocation) -> Weight {
|
||||
assets.weigh_multi_assets(XcmBalancesWeight::<Runtime>::deposit_asset())
|
||||
}
|
||||
fn deposit_reserve_asset(
|
||||
assets: &MultiAssetFilter,
|
||||
_max_assets: &u32, // TODO use max assets?
|
||||
_dest: &MultiLocation,
|
||||
_xcm: &Xcm<()>,
|
||||
) -> XCMWeight {
|
||||
) -> Weight {
|
||||
assets.weigh_multi_assets(XcmBalancesWeight::<Runtime>::deposit_reserve_asset())
|
||||
}
|
||||
fn exchange_asset(_give: &MultiAssetFilter, _receive: &MultiAssets) -> XCMWeight {
|
||||
Weight::MAX.ref_time() // todo fix
|
||||
fn exchange_asset(_give: &MultiAssetFilter, _receive: &MultiAssets, _maximal: &bool) -> Weight {
|
||||
// Westend does not currently support exchange asset operations
|
||||
Weight::MAX
|
||||
}
|
||||
fn initiate_reserve_withdraw(
|
||||
assets: &MultiAssetFilter,
|
||||
_reserve: &MultiLocation,
|
||||
_xcm: &Xcm<()>,
|
||||
) -> XCMWeight {
|
||||
) -> Weight {
|
||||
assets.weigh_multi_assets(XcmGeneric::<Runtime>::initiate_reserve_withdraw())
|
||||
}
|
||||
fn initiate_teleport(
|
||||
assets: &MultiAssetFilter,
|
||||
_dest: &MultiLocation,
|
||||
_xcm: &Xcm<()>,
|
||||
) -> XCMWeight {
|
||||
) -> Weight {
|
||||
assets.weigh_multi_assets(XcmBalancesWeight::<Runtime>::initiate_teleport())
|
||||
}
|
||||
fn query_holding(
|
||||
_query_id: &u64,
|
||||
_dest: &MultiLocation,
|
||||
_assets: &MultiAssetFilter,
|
||||
_max_response_weight: &u64,
|
||||
) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::query_holding().ref_time()
|
||||
fn report_holding(_response_info: &QueryResponseInfo, _assets: &MultiAssetFilter) -> Weight {
|
||||
XcmGeneric::<Runtime>::report_holding()
|
||||
}
|
||||
fn buy_execution(_fees: &MultiAsset, _weight_limit: &WeightLimit) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::buy_execution().ref_time()
|
||||
fn buy_execution(_fees: &MultiAsset, _weight_limit: &WeightLimit) -> Weight {
|
||||
XcmGeneric::<Runtime>::buy_execution()
|
||||
}
|
||||
fn refund_surplus() -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::refund_surplus().ref_time()
|
||||
fn refund_surplus() -> Weight {
|
||||
XcmGeneric::<Runtime>::refund_surplus()
|
||||
}
|
||||
fn set_error_handler(_xcm: &Xcm<RuntimeCall>) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::set_error_handler().ref_time()
|
||||
fn set_error_handler(_xcm: &Xcm<RuntimeCall>) -> Weight {
|
||||
XcmGeneric::<Runtime>::set_error_handler()
|
||||
}
|
||||
fn set_appendix(_xcm: &Xcm<RuntimeCall>) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::set_appendix().ref_time()
|
||||
fn set_appendix(_xcm: &Xcm<RuntimeCall>) -> Weight {
|
||||
XcmGeneric::<Runtime>::set_appendix()
|
||||
}
|
||||
fn clear_error() -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::clear_error().ref_time()
|
||||
fn clear_error() -> Weight {
|
||||
XcmGeneric::<Runtime>::clear_error()
|
||||
}
|
||||
fn claim_asset(_assets: &MultiAssets, _ticket: &MultiLocation) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::claim_asset().ref_time()
|
||||
fn claim_asset(_assets: &MultiAssets, _ticket: &MultiLocation) -> Weight {
|
||||
XcmGeneric::<Runtime>::claim_asset()
|
||||
}
|
||||
fn trap(_code: &u64) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::trap().ref_time()
|
||||
fn trap(_code: &u64) -> Weight {
|
||||
XcmGeneric::<Runtime>::trap()
|
||||
}
|
||||
fn subscribe_version(_query_id: &QueryId, _max_response_weight: &u64) -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::subscribe_version().ref_time()
|
||||
fn subscribe_version(_query_id: &QueryId, _max_response_weight: &Weight) -> Weight {
|
||||
XcmGeneric::<Runtime>::subscribe_version()
|
||||
}
|
||||
fn unsubscribe_version() -> XCMWeight {
|
||||
XcmGeneric::<Runtime>::unsubscribe_version().ref_time()
|
||||
fn unsubscribe_version() -> Weight {
|
||||
XcmGeneric::<Runtime>::unsubscribe_version()
|
||||
}
|
||||
fn burn_asset(assets: &MultiAssets) -> Weight {
|
||||
assets.weigh_multi_assets(XcmGeneric::<Runtime>::burn_asset())
|
||||
}
|
||||
fn expect_asset(assets: &MultiAssets) -> Weight {
|
||||
assets.weigh_multi_assets(XcmGeneric::<Runtime>::expect_asset())
|
||||
}
|
||||
fn expect_origin(_origin: &Option<MultiLocation>) -> Weight {
|
||||
XcmGeneric::<Runtime>::expect_origin()
|
||||
}
|
||||
fn expect_error(_error: &Option<(u32, XcmError)>) -> Weight {
|
||||
XcmGeneric::<Runtime>::expect_error()
|
||||
}
|
||||
fn query_pallet(_module_name: &Vec<u8>, _response_info: &QueryResponseInfo) -> Weight {
|
||||
XcmGeneric::<Runtime>::query_pallet()
|
||||
}
|
||||
fn expect_pallet(
|
||||
_index: &u32,
|
||||
_name: &Vec<u8>,
|
||||
_module_name: &Vec<u8>,
|
||||
_crate_major: &u32,
|
||||
_min_crate_minor: &u32,
|
||||
) -> Weight {
|
||||
XcmGeneric::<Runtime>::expect_pallet()
|
||||
}
|
||||
fn report_transact_status(_response_info: &QueryResponseInfo) -> Weight {
|
||||
XcmGeneric::<Runtime>::report_transact_status()
|
||||
}
|
||||
fn clear_transact_status() -> Weight {
|
||||
XcmGeneric::<Runtime>::clear_transact_status()
|
||||
}
|
||||
fn universal_origin(_: &Junction) -> Weight {
|
||||
// Westend does not currently support universal origin operations
|
||||
Weight::MAX
|
||||
}
|
||||
fn export_message(_: &NetworkId, _: &Junctions, _: &Xcm<()>) -> Weight {
|
||||
// Westend does not currently support export message operations
|
||||
Weight::MAX
|
||||
}
|
||||
fn lock_asset(_: &MultiAsset, _: &MultiLocation) -> Weight {
|
||||
// Westend does not currently support asset locking operations
|
||||
Weight::MAX
|
||||
}
|
||||
fn unlock_asset(_: &MultiAsset, _: &MultiLocation) -> Weight {
|
||||
// Westend does not currently support asset locking operations
|
||||
Weight::MAX
|
||||
}
|
||||
fn note_unlockable(_: &MultiAsset, _: &MultiLocation) -> Weight {
|
||||
// Westend does not currently support asset locking operations
|
||||
Weight::MAX
|
||||
}
|
||||
fn request_unlock(_: &MultiAsset, _: &MultiLocation) -> Weight {
|
||||
// Westend does not currently support asset locking operations
|
||||
Weight::MAX
|
||||
}
|
||||
fn set_fees_mode(_: &bool) -> Weight {
|
||||
XcmGeneric::<Runtime>::set_fees_mode()
|
||||
}
|
||||
fn set_topic(_topic: &[u8; 32]) -> Weight {
|
||||
XcmGeneric::<Runtime>::set_topic()
|
||||
}
|
||||
fn clear_topic() -> Weight {
|
||||
XcmGeneric::<Runtime>::clear_topic()
|
||||
}
|
||||
fn alias_origin(_: &MultiLocation) -> Weight {
|
||||
// XCM Executor does not currently support alias origin operations
|
||||
Weight::MAX
|
||||
}
|
||||
fn unpaid_execution(_: &WeightLimit, _: &Option<MultiLocation>) -> Weight {
|
||||
XcmGeneric::<Runtime>::unpaid_execution()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2017-2021 Parity Technologies (UK) Ltd.
|
||||
// Copyright 2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Polkadot.
|
||||
|
||||
// Polkadot is free software: you can redistribute it and/or modify
|
||||
@@ -17,23 +17,25 @@
|
||||
//! Autogenerated weights for `pallet_xcm_benchmarks::generic`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2021-12-01, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 128
|
||||
//! DATE: 2022-12-12, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024
|
||||
|
||||
// Executed Command:
|
||||
// target/release/polkadot
|
||||
// /home/benchbot/cargo_target_dir/production/polkadot
|
||||
// benchmark
|
||||
// --chain=westend-dev
|
||||
// pallet
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
// --pallet=pallet_xcm_benchmarks::generic
|
||||
// --extrinsic=*
|
||||
// --execution=wasm
|
||||
// --wasm-execution=compiled
|
||||
// --heap-pages=4096
|
||||
// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/polkadot/.git/.artifacts/bench.json
|
||||
// --pallet=pallet_xcm_benchmarks::generic
|
||||
// --chain=westend-dev
|
||||
// --header=./file_header.txt
|
||||
// --template=./xcm/pallet-xcm-benchmarks/template.hbs
|
||||
// --output=./runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
|
||||
// --output=./runtime/westend/src/weights/xcm/
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
@@ -48,85 +50,135 @@ impl<T: frame_system::Config> WeightInfo<T> {
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
pub(crate) fn query_holding() -> Weight {
|
||||
Weight::from_ref_time(39_278_000 as u64)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
pub(crate) fn report_holding() -> Weight {
|
||||
Weight::from_ref_time(34_089_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(5 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as u64))
|
||||
}
|
||||
pub(crate) fn buy_execution() -> Weight {
|
||||
Weight::from_ref_time(5_922_000 as u64)
|
||||
Weight::from_ref_time(5_751_000 as u64)
|
||||
}
|
||||
// Storage: XcmPallet Queries (r:1 w:0)
|
||||
pub(crate) fn query_response() -> Weight {
|
||||
Weight::from_ref_time(20_625_000 as u64)
|
||||
Weight::from_ref_time(17_938_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(1 as u64))
|
||||
}
|
||||
pub(crate) fn transact() -> Weight {
|
||||
Weight::from_ref_time(22_198_000 as u64)
|
||||
Weight::from_ref_time(20_699_000 as u64)
|
||||
}
|
||||
pub(crate) fn refund_surplus() -> Weight {
|
||||
Weight::from_ref_time(6_122_000 as u64)
|
||||
Weight::from_ref_time(6_077_000 as u64)
|
||||
}
|
||||
pub(crate) fn set_error_handler() -> Weight {
|
||||
Weight::from_ref_time(5_758_000 as u64)
|
||||
Weight::from_ref_time(5_747_000 as u64)
|
||||
}
|
||||
pub(crate) fn set_appendix() -> Weight {
|
||||
Weight::from_ref_time(5_764_000 as u64)
|
||||
Weight::from_ref_time(5_837_000 as u64)
|
||||
}
|
||||
pub(crate) fn clear_error() -> Weight {
|
||||
Weight::from_ref_time(5_679_000 as u64)
|
||||
Weight::from_ref_time(5_712_000 as u64)
|
||||
}
|
||||
pub(crate) fn descend_origin() -> Weight {
|
||||
Weight::from_ref_time(7_206_000 as u64)
|
||||
Weight::from_ref_time(6_471_000 as u64)
|
||||
}
|
||||
pub(crate) fn clear_origin() -> Weight {
|
||||
Weight::from_ref_time(5_738_000 as u64)
|
||||
Weight::from_ref_time(5_725_000 as u64)
|
||||
}
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
pub(crate) fn report_error() -> Weight {
|
||||
Weight::from_ref_time(31_512_000 as u64)
|
||||
Weight::from_ref_time(29_975_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(5 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as u64))
|
||||
}
|
||||
// Storage: XcmPallet AssetTraps (r:1 w:1)
|
||||
pub(crate) fn claim_asset() -> Weight {
|
||||
Weight::from_ref_time(13_594_000 as u64)
|
||||
Weight::from_ref_time(21_598_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(1 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as u64))
|
||||
}
|
||||
pub(crate) fn trap() -> Weight {
|
||||
Weight::from_ref_time(5_745_000 as u64)
|
||||
Weight::from_ref_time(5_665_000 as u64)
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifyTargets (r:1 w:1)
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
pub(crate) fn subscribe_version() -> Weight {
|
||||
Weight::from_ref_time(38_138_000 as u64)
|
||||
Weight::from_ref_time(38_343_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(6 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(4 as u64))
|
||||
}
|
||||
// Storage: XcmPallet VersionNotifyTargets (r:0 w:1)
|
||||
pub(crate) fn unsubscribe_version() -> Weight {
|
||||
Weight::from_ref_time(9_127_000 as u64)
|
||||
Weight::from_ref_time(8_353_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().writes(1 as u64))
|
||||
}
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
pub(crate) fn initiate_reserve_withdraw() -> Weight {
|
||||
Weight::from_ref_time(41_443_000 as u64)
|
||||
Weight::from_ref_time(33_100_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(5 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as u64))
|
||||
}
|
||||
pub(crate) fn burn_asset() -> Weight {
|
||||
Weight::from_ref_time(7_259_000 as u64)
|
||||
}
|
||||
pub(crate) fn expect_asset() -> Weight {
|
||||
Weight::from_ref_time(5_848_000 as u64)
|
||||
}
|
||||
pub(crate) fn expect_origin() -> Weight {
|
||||
Weight::from_ref_time(5_787_000 as u64)
|
||||
}
|
||||
pub(crate) fn expect_error() -> Weight {
|
||||
Weight::from_ref_time(5_775_000 as u64)
|
||||
}
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
pub(crate) fn query_pallet() -> Weight {
|
||||
Weight::from_ref_time(34_846_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(5 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as u64))
|
||||
}
|
||||
pub(crate) fn expect_pallet() -> Weight {
|
||||
Weight::from_ref_time(8_844_000 as u64)
|
||||
}
|
||||
// Storage: XcmPallet SupportedVersion (r:1 w:0)
|
||||
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
|
||||
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
|
||||
pub(crate) fn report_transact_status() -> Weight {
|
||||
Weight::from_ref_time(50_256_000 as u64)
|
||||
.saturating_add(T::DbWeight::get().reads(5 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as u64))
|
||||
}
|
||||
pub(crate) fn clear_transact_status() -> Weight {
|
||||
Weight::from_ref_time(9_959_000 as u64)
|
||||
}
|
||||
pub(crate) fn set_topic() -> Weight {
|
||||
Weight::from_ref_time(10_007_000 as u64)
|
||||
}
|
||||
pub(crate) fn clear_topic() -> Weight {
|
||||
Weight::from_ref_time(8_289_000 as u64)
|
||||
}
|
||||
pub(crate) fn set_fees_mode() -> Weight {
|
||||
Weight::from_ref_time(5_764_000 as u64)
|
||||
}
|
||||
pub(crate) fn unpaid_execution() -> Weight {
|
||||
Weight::from_ref_time(5_924_000 as u64)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,52 +17,54 @@
|
||||
//! XCM configurations for Westend.
|
||||
|
||||
use super::{
|
||||
parachains_origin, weights, AccountId, Balances, ParaId, Runtime, RuntimeCall, RuntimeEvent,
|
||||
RuntimeOrigin, WeightToFee, XcmPallet,
|
||||
parachains_origin, weights, AccountId, AllPalletsWithSystem, Balances, ParaId, Runtime,
|
||||
RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmPallet,
|
||||
};
|
||||
use frame_support::{
|
||||
parameter_types,
|
||||
traits::{Everything, Nothing},
|
||||
traits::{Contains, Everything, Nothing},
|
||||
};
|
||||
use runtime_common::{xcm_sender, ToAuthor};
|
||||
use sp_core::ConstU32;
|
||||
use xcm::latest::prelude::*;
|
||||
use xcm_builder::{
|
||||
AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom,
|
||||
AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, ChildParachainAsNative,
|
||||
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
|
||||
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative,
|
||||
ChildParachainConvertsVia, ChildSystemParachainAsSuperuser,
|
||||
CurrencyAdapter as XcmCurrencyAdapter, IsChildSystemParachain, IsConcrete, LocationInverter,
|
||||
CurrencyAdapter as XcmCurrencyAdapter, IsChildSystemParachain, IsConcrete, MintLocation,
|
||||
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
|
||||
UsingComponents, WeightInfoBounds,
|
||||
UsingComponents, WeightInfoBounds, WithComputedOrigin,
|
||||
};
|
||||
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
|
||||
|
||||
parameter_types! {
|
||||
pub const WndLocation: MultiLocation = Here.into();
|
||||
pub const Ancestry: MultiLocation = Here.into();
|
||||
pub WestendNetwork: NetworkId =
|
||||
NetworkId::Named(b"Westend".to_vec().try_into().expect("shorter than length limit; qed"));
|
||||
pub const TokenLocation: MultiLocation = Here.into_location();
|
||||
pub const ThisNetwork: NetworkId = Westend;
|
||||
pub UniversalLocation: InteriorMultiLocation = ThisNetwork::get().into();
|
||||
pub CheckAccount: AccountId = XcmPallet::check_account();
|
||||
pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local);
|
||||
}
|
||||
|
||||
pub type LocationConverter =
|
||||
(ChildParachainConvertsVia<ParaId, AccountId>, AccountId32Aliases<WestendNetwork, AccountId>);
|
||||
(ChildParachainConvertsVia<ParaId, AccountId>, AccountId32Aliases<ThisNetwork, AccountId>);
|
||||
|
||||
pub type LocalAssetTransactor = XcmCurrencyAdapter<
|
||||
// Use this currency:
|
||||
Balances,
|
||||
// Use this currency when it is a fungible asset matching the given location or name:
|
||||
IsConcrete<WndLocation>,
|
||||
IsConcrete<TokenLocation>,
|
||||
// We can convert the MultiLocations with our converter above:
|
||||
LocationConverter,
|
||||
// Our chain's account ID type (we can't get away without mentioning it explicitly):
|
||||
AccountId,
|
||||
// It's a native asset so we keep track of the teleports to maintain total issuance.
|
||||
CheckAccount,
|
||||
LocalCheckAccount,
|
||||
>;
|
||||
|
||||
type LocalOriginConverter = (
|
||||
SovereignSignedViaLocation<LocationConverter, RuntimeOrigin>,
|
||||
ChildParachainAsNative<parachains_origin::Origin, RuntimeOrigin>,
|
||||
SignedAccountId32AsNative<WestendNetwork, RuntimeOrigin>,
|
||||
SignedAccountId32AsNative<ThisNetwork, RuntimeOrigin>,
|
||||
ChildSystemParachainAsSuperuser<ParaId, RuntimeOrigin>,
|
||||
);
|
||||
|
||||
@@ -70,35 +72,143 @@ type LocalOriginConverter = (
|
||||
/// individual routers.
|
||||
pub type XcmRouter = (
|
||||
// Only one router so far - use DMP to communicate with child parachains.
|
||||
xcm_sender::ChildParachainRouter<Runtime, XcmPallet>,
|
||||
xcm_sender::ChildParachainRouter<Runtime, XcmPallet, ()>,
|
||||
);
|
||||
|
||||
parameter_types! {
|
||||
pub const Westmint: MultiLocation = Parachain(1000).into();
|
||||
pub const Collectives: MultiLocation = Parachain(1001).into();
|
||||
pub const WestendForWestmint: (MultiAssetFilter, MultiLocation) =
|
||||
(Wild(AllOf { fun: WildFungible, id: Concrete(WndLocation::get()) }), Westmint::get());
|
||||
pub const WestendForCollectives: (MultiAssetFilter, MultiLocation) =
|
||||
(Wild(AllOf { fun: WildFungible, id: Concrete(WndLocation::get()) }), Collectives::get());
|
||||
pub const Westmint: MultiLocation = Parachain(1000).into_location();
|
||||
pub const Collectives: MultiLocation = Parachain(1001).into_location();
|
||||
pub const Wnd: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) });
|
||||
pub const WndForWestmint: (MultiAssetFilter, MultiLocation) = (Wnd::get(), Westmint::get());
|
||||
pub const WndForCollectives: (MultiAssetFilter, MultiLocation) = (Wnd::get(), Collectives::get());
|
||||
pub const MaxInstructions: u32 = 100;
|
||||
pub const MaxAssetsIntoHolding: u32 = 64;
|
||||
}
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
parameter_types! {
|
||||
pub ReachableDest: Option<MultiLocation> = Some(Parachain(1000).into());
|
||||
}
|
||||
|
||||
pub type TrustedTeleporters =
|
||||
(xcm_builder::Case<WestendForWestmint>, xcm_builder::Case<WestendForCollectives>);
|
||||
(xcm_builder::Case<WndForWestmint>, xcm_builder::Case<WndForCollectives>);
|
||||
|
||||
/// The barriers one of which must be passed for an XCM message to be executed.
|
||||
pub type Barrier = (
|
||||
// Weight that is paid for may be consumed.
|
||||
TakeWeightCredit,
|
||||
// If the message is one that immediately attemps to pay for execution, then allow it.
|
||||
AllowTopLevelPaidExecutionFrom<Everything>,
|
||||
// Messages coming from system parachains need not pay for execution.
|
||||
AllowUnpaidExecutionFrom<IsChildSystemParachain<ParaId>>,
|
||||
// Expected responses are OK.
|
||||
AllowKnownQueryResponses<XcmPallet>,
|
||||
// Subscriptions for version tracking are OK.
|
||||
AllowSubscriptionsFrom<Everything>,
|
||||
WithComputedOrigin<
|
||||
(
|
||||
// If the message is one that immediately attemps to pay for execution, then allow it.
|
||||
AllowTopLevelPaidExecutionFrom<Everything>,
|
||||
// Messages coming from system parachains need not pay for execution.
|
||||
AllowExplicitUnpaidExecutionFrom<IsChildSystemParachain<ParaId>>,
|
||||
// Subscriptions for version tracking are OK.
|
||||
AllowSubscriptionsFrom<Everything>,
|
||||
),
|
||||
UniversalLocation,
|
||||
ConstU32<8>,
|
||||
>,
|
||||
);
|
||||
|
||||
/// A call filter for the XCM Transact instruction. This is a temporary measure until we
|
||||
/// properly account for proof size weights.
|
||||
///
|
||||
/// Calls that are allowed through this filter must:
|
||||
/// 1. Have a fixed weight;
|
||||
/// 2. Cannot lead to another call being made;
|
||||
/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call parameters.
|
||||
pub struct SafeCallFilter;
|
||||
impl Contains<RuntimeCall> for SafeCallFilter {
|
||||
fn contains(call: &RuntimeCall) -> bool {
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
{
|
||||
if matches!(call, RuntimeCall::System(frame_system::Call::remark_with_event { .. })) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
match call {
|
||||
RuntimeCall::System(
|
||||
frame_system::Call::kill_prefix { .. } | frame_system::Call::set_heap_pages { .. },
|
||||
) |
|
||||
RuntimeCall::Babe(..) |
|
||||
RuntimeCall::Timestamp(..) |
|
||||
RuntimeCall::Indices(..) |
|
||||
RuntimeCall::Balances(..) |
|
||||
RuntimeCall::Staking(
|
||||
pallet_staking::Call::bond { .. } |
|
||||
pallet_staking::Call::bond_extra { .. } |
|
||||
pallet_staking::Call::unbond { .. } |
|
||||
pallet_staking::Call::withdraw_unbonded { .. } |
|
||||
pallet_staking::Call::validate { .. } |
|
||||
pallet_staking::Call::nominate { .. } |
|
||||
pallet_staking::Call::chill { .. } |
|
||||
pallet_staking::Call::set_payee { .. } |
|
||||
pallet_staking::Call::set_controller { .. } |
|
||||
pallet_staking::Call::set_validator_count { .. } |
|
||||
pallet_staking::Call::increase_validator_count { .. } |
|
||||
pallet_staking::Call::scale_validator_count { .. } |
|
||||
pallet_staking::Call::force_no_eras { .. } |
|
||||
pallet_staking::Call::force_new_era { .. } |
|
||||
pallet_staking::Call::set_invulnerables { .. } |
|
||||
pallet_staking::Call::force_unstake { .. } |
|
||||
pallet_staking::Call::force_new_era_always { .. } |
|
||||
pallet_staking::Call::payout_stakers { .. } |
|
||||
pallet_staking::Call::rebond { .. } |
|
||||
pallet_staking::Call::reap_stash { .. } |
|
||||
pallet_staking::Call::set_staking_configs { .. } |
|
||||
pallet_staking::Call::chill_other { .. } |
|
||||
pallet_staking::Call::force_apply_min_commission { .. },
|
||||
) |
|
||||
RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) |
|
||||
RuntimeCall::Grandpa(..) |
|
||||
RuntimeCall::ImOnline(..) |
|
||||
RuntimeCall::Utility(pallet_utility::Call::as_derivative { .. }) |
|
||||
RuntimeCall::Identity(
|
||||
pallet_identity::Call::add_registrar { .. } |
|
||||
pallet_identity::Call::set_identity { .. } |
|
||||
pallet_identity::Call::clear_identity { .. } |
|
||||
pallet_identity::Call::request_judgement { .. } |
|
||||
pallet_identity::Call::cancel_request { .. } |
|
||||
pallet_identity::Call::set_fee { .. } |
|
||||
pallet_identity::Call::set_account_id { .. } |
|
||||
pallet_identity::Call::set_fields { .. } |
|
||||
pallet_identity::Call::provide_judgement { .. } |
|
||||
pallet_identity::Call::kill_identity { .. } |
|
||||
pallet_identity::Call::add_sub { .. } |
|
||||
pallet_identity::Call::rename_sub { .. } |
|
||||
pallet_identity::Call::remove_sub { .. } |
|
||||
pallet_identity::Call::quit_sub { .. },
|
||||
) |
|
||||
RuntimeCall::Recovery(..) |
|
||||
RuntimeCall::Vesting(..) |
|
||||
RuntimeCall::ElectionProviderMultiPhase(..) |
|
||||
RuntimeCall::VoterList(..) |
|
||||
RuntimeCall::NominationPools(
|
||||
pallet_nomination_pools::Call::join { .. } |
|
||||
pallet_nomination_pools::Call::bond_extra { .. } |
|
||||
pallet_nomination_pools::Call::claim_payout { .. } |
|
||||
pallet_nomination_pools::Call::unbond { .. } |
|
||||
pallet_nomination_pools::Call::pool_withdraw_unbonded { .. } |
|
||||
pallet_nomination_pools::Call::withdraw_unbonded { .. } |
|
||||
pallet_nomination_pools::Call::create { .. } |
|
||||
pallet_nomination_pools::Call::create_with_pool_id { .. } |
|
||||
pallet_nomination_pools::Call::set_state { .. } |
|
||||
pallet_nomination_pools::Call::set_configs { .. } |
|
||||
pallet_nomination_pools::Call::update_roles { .. } |
|
||||
pallet_nomination_pools::Call::chill { .. },
|
||||
) |
|
||||
RuntimeCall::XcmPallet(pallet_xcm::Call::limited_reserve_transfer_assets {
|
||||
..
|
||||
}) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct XcmConfig;
|
||||
impl xcm_executor::Config for XcmConfig {
|
||||
type RuntimeCall = RuntimeCall;
|
||||
@@ -107,22 +217,32 @@ impl xcm_executor::Config for XcmConfig {
|
||||
type OriginConverter = LocalOriginConverter;
|
||||
type IsReserve = ();
|
||||
type IsTeleporter = TrustedTeleporters;
|
||||
type LocationInverter = LocationInverter<Ancestry>;
|
||||
type UniversalLocation = UniversalLocation;
|
||||
type Barrier = Barrier;
|
||||
type Weigher =
|
||||
WeightInfoBounds<weights::xcm::WestendXcmWeight<RuntimeCall>, RuntimeCall, MaxInstructions>;
|
||||
type Trader = UsingComponents<WeightToFee, WndLocation, AccountId, Balances, ToAuthor<Runtime>>;
|
||||
type Trader =
|
||||
UsingComponents<WeightToFee, TokenLocation, AccountId, Balances, ToAuthor<Runtime>>;
|
||||
type ResponseHandler = XcmPallet;
|
||||
type AssetTrap = XcmPallet;
|
||||
type AssetLocker = ();
|
||||
type AssetExchanger = ();
|
||||
type AssetClaims = XcmPallet;
|
||||
type SubscriptionService = XcmPallet;
|
||||
type PalletInstancesInfo = AllPalletsWithSystem;
|
||||
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
|
||||
type FeeManager = ();
|
||||
type MessageExporter = ();
|
||||
type UniversalAliases = Nothing;
|
||||
type CallDispatcher = WithOriginFilter<SafeCallFilter>;
|
||||
type SafeCallFilter = SafeCallFilter;
|
||||
}
|
||||
|
||||
/// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior location
|
||||
/// of this chain.
|
||||
pub type LocalOriginToLocation = (
|
||||
// And a usual Signed origin to be used in XCM as a corresponding AccountId32
|
||||
SignedToAccountId32<RuntimeOrigin, AccountId, WestendNetwork>,
|
||||
SignedToAccountId32<RuntimeOrigin, AccountId, ThisNetwork>,
|
||||
);
|
||||
|
||||
impl pallet_xcm::Config for Runtime {
|
||||
@@ -133,14 +253,22 @@ impl pallet_xcm::Config for Runtime {
|
||||
type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
|
||||
// ...but they must match our filter, which rejects everything.
|
||||
type XcmExecuteFilter = Nothing;
|
||||
type XcmExecutor = xcm_executor::XcmExecutor<XcmConfig>;
|
||||
type XcmExecutor = XcmExecutor<XcmConfig>;
|
||||
type XcmTeleportFilter = Everything;
|
||||
type XcmReserveTransferFilter = Everything;
|
||||
type Weigher =
|
||||
WeightInfoBounds<weights::xcm::WestendXcmWeight<RuntimeCall>, RuntimeCall, MaxInstructions>;
|
||||
type LocationInverter = LocationInverter<Ancestry>;
|
||||
type UniversalLocation = UniversalLocation;
|
||||
type RuntimeOrigin = RuntimeOrigin;
|
||||
type RuntimeCall = RuntimeCall;
|
||||
const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
|
||||
type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
|
||||
type Currency = Balances;
|
||||
type CurrencyMatcher = IsConcrete<TokenLocation>;
|
||||
type TrustedLockers = ();
|
||||
type SovereignAccountOf = LocationConverter;
|
||||
type MaxLockers = ConstU32<8>;
|
||||
type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type ReachableDest = ReachableDest;
|
||||
}
|
||||
|
||||
@@ -163,6 +163,7 @@ MQC/SM
|
||||
msg
|
||||
multisig/S
|
||||
multivalidator/SM
|
||||
mutators
|
||||
mutex
|
||||
natively
|
||||
NFA
|
||||
@@ -220,6 +221,7 @@ proxy/G
|
||||
proxying
|
||||
PRs
|
||||
PVF/S
|
||||
querier
|
||||
README/MS
|
||||
redhat/M
|
||||
register/CD
|
||||
@@ -254,6 +256,7 @@ SS58
|
||||
SSL
|
||||
startup/MS
|
||||
stateful
|
||||
Statemine
|
||||
str
|
||||
struct/MS
|
||||
subcommand/SM
|
||||
@@ -291,6 +294,7 @@ UI
|
||||
unapplied
|
||||
unassign
|
||||
unconcluded
|
||||
unexpectable
|
||||
unfinalize/B
|
||||
unfinalized
|
||||
union/MSG
|
||||
|
||||
+12
-8
@@ -6,22 +6,26 @@ authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[dependencies]
|
||||
derivative = { version = "2.2.0", default-features = false, features = [ "use_core" ] }
|
||||
impl-trait-for-tuples = "0.2.2"
|
||||
parity-scale-codec = { version = "3.1.5", default-features = false, features = ["derive", "max-encoded-len"] }
|
||||
scale-info = { version = "2.1.2", default-features = false, features = ["derive"] }
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
derivative = {version = "2.2.0", default-features = false, features = [ "use_core" ] }
|
||||
log = { version = "0.4.17", default-features = false }
|
||||
parity-scale-codec = { version = "3.1.5", default-features = false, features = [ "derive", "max-encoded-len" ] }
|
||||
scale-info = { version = "2.1.2", default-features = false, features = ["derive"] }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-weights = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
serde = { version = "1.0.136", optional = true, features = ["derive"] }
|
||||
xcm-procedural = { path = "procedural" }
|
||||
|
||||
[dev-dependencies]
|
||||
sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
wasm-api = []
|
||||
runtime-benchmarks = [
|
||||
"sp-runtime/runtime-benchmarks",
|
||||
]
|
||||
std = [
|
||||
"parity-scale-codec/std",
|
||||
"scale-info/std",
|
||||
"sp-runtime/std",
|
||||
"serde",
|
||||
"sp-core/std",
|
||||
"sp-weights/std",
|
||||
]
|
||||
|
||||
@@ -14,18 +14,18 @@ frame-support = { default-features = false, branch = "master", git = "https://gi
|
||||
frame-system = { default-features = false, branch = "master", git = "https://github.com/paritytech/substrate" }
|
||||
sp-runtime = { default-features = false, branch = "master", git = "https://github.com/paritytech/substrate" }
|
||||
sp-std = { default-features = false, branch = "master", git = "https://github.com/paritytech/substrate" }
|
||||
sp-io = { default-features = false, branch = "master", git = "https://github.com/paritytech/substrate" }
|
||||
xcm-executor = { path = "../xcm-executor", default-features = false }
|
||||
frame-benchmarking = { default-features = false, branch = "master", git = "https://github.com/paritytech/substrate" }
|
||||
xcm = { path = "..", default-features = false }
|
||||
xcm-builder = { path = "../xcm-builder", default-features = false }
|
||||
log = "0.4.17"
|
||||
|
||||
[dev-dependencies]
|
||||
pallet-balances = { branch = "master", git = "https://github.com/paritytech/substrate" }
|
||||
pallet-assets = { branch = "master", git = "https://github.com/paritytech/substrate" }
|
||||
sp-core = { branch = "master", git = "https://github.com/paritytech/substrate" }
|
||||
sp-io = { branch = "master", git = "https://github.com/paritytech/substrate" }
|
||||
sp-tracing = { branch = "master", git = "https://github.com/paritytech/substrate" }
|
||||
xcm-builder = { path = "../xcm-builder" }
|
||||
xcm = { path = ".." }
|
||||
# temp
|
||||
pallet-xcm = { path = "../pallet-xcm" }
|
||||
@@ -40,11 +40,14 @@ std = [
|
||||
"frame-benchmarking/std",
|
||||
"frame-support/std",
|
||||
"frame-system/std",
|
||||
"sp-io/std",
|
||||
"sp-runtime/std",
|
||||
"sp-std/std"
|
||||
"sp-std/std",
|
||||
"xcm-builder/std",
|
||||
"xcm-executor/std"
|
||||
]
|
||||
runtime-benchmarks = [
|
||||
"xcm/runtime-benchmarks",
|
||||
"xcm-builder/runtime-benchmarks",
|
||||
"xcm-executor/runtime-benchmarks",
|
||||
"frame-benchmarking/runtime-benchmarks",
|
||||
"frame-support/runtime-benchmarks",
|
||||
|
||||
@@ -41,23 +41,31 @@ benchmarks_instance_pallet! {
|
||||
|
||||
withdraw_asset {
|
||||
let (sender_account, sender_location) = account_and_location::<T>(1);
|
||||
let worst_case_holding = T::worst_case_holding();
|
||||
let worst_case_holding = T::worst_case_holding(0);
|
||||
let asset = T::get_multi_asset();
|
||||
|
||||
<AssetTransactorOf<T>>::deposit_asset(&asset, &sender_location).unwrap();
|
||||
<AssetTransactorOf<T>>::deposit_asset(
|
||||
&asset,
|
||||
&sender_location,
|
||||
&XcmContext {
|
||||
origin: Some(sender_location.clone()),
|
||||
message_hash: [0; 32],
|
||||
topic: None,
|
||||
},
|
||||
).unwrap();
|
||||
// check the assets of origin.
|
||||
assert!(!T::TransactAsset::balance(&sender_account).is_zero());
|
||||
|
||||
let mut executor = new_executor::<T>(sender_location);
|
||||
executor.holding = worst_case_holding.into();
|
||||
executor.set_holding(worst_case_holding.into());
|
||||
let instruction = Instruction::<XcmCallOf<T>>::WithdrawAsset(vec![asset.clone()].into());
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}: {
|
||||
executor.execute(xcm)?;
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
// check one of the assets of origin.
|
||||
assert!(T::TransactAsset::balance(&sender_account).is_zero());
|
||||
assert!(executor.holding.ensure_contains(&vec![asset].into()).is_ok());
|
||||
assert!(executor.holding().ensure_contains(&vec![asset].into()).is_ok());
|
||||
}
|
||||
|
||||
transfer_asset {
|
||||
@@ -69,14 +77,22 @@ benchmarks_instance_pallet! {
|
||||
let dest_location = T::valid_destination()?;
|
||||
let dest_account = T::AccountIdConverter::convert(dest_location.clone()).unwrap();
|
||||
|
||||
<AssetTransactorOf<T>>::deposit_asset(&asset, &sender_location).unwrap();
|
||||
<AssetTransactorOf<T>>::deposit_asset(
|
||||
&asset,
|
||||
&sender_location,
|
||||
&XcmContext {
|
||||
origin: Some(sender_location.clone()),
|
||||
message_hash: [0; 32],
|
||||
topic: None,
|
||||
},
|
||||
).unwrap();
|
||||
assert!(T::TransactAsset::balance(&dest_account).is_zero());
|
||||
|
||||
let mut executor = new_executor::<T>(sender_location);
|
||||
let instruction = Instruction::TransferAsset { assets, beneficiary: dest_location };
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}: {
|
||||
executor.execute(xcm)?;
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
assert!(T::TransactAsset::balance(&sender_account).is_zero());
|
||||
assert!(!T::TransactAsset::balance(&dest_account).is_zero());
|
||||
@@ -88,7 +104,15 @@ benchmarks_instance_pallet! {
|
||||
let dest_account = T::AccountIdConverter::convert(dest_location.clone()).unwrap();
|
||||
|
||||
let asset = T::get_multi_asset();
|
||||
<AssetTransactorOf<T>>::deposit_asset(&asset, &sender_location).unwrap();
|
||||
<AssetTransactorOf<T>>::deposit_asset(
|
||||
&asset,
|
||||
&sender_location,
|
||||
&XcmContext {
|
||||
origin: Some(sender_location.clone()),
|
||||
message_hash: [0; 32],
|
||||
topic: None,
|
||||
},
|
||||
).unwrap();
|
||||
let assets: MultiAssets = vec![ asset ].into();
|
||||
assert!(T::TransactAsset::balance(&dest_account).is_zero());
|
||||
|
||||
@@ -100,38 +124,19 @@ benchmarks_instance_pallet! {
|
||||
};
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}: {
|
||||
executor.execute(xcm)?;
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
assert!(T::TransactAsset::balance(&sender_account).is_zero());
|
||||
assert!(!T::TransactAsset::balance(&dest_account).is_zero());
|
||||
// TODO: Check sender queue is not empty. #4426
|
||||
}
|
||||
|
||||
reserve_asset_deposited {
|
||||
let (trusted_reserve, transferable_reserve_asset) = T::TrustedReserve::get()
|
||||
.ok_or(BenchmarkError::Skip)?;
|
||||
|
||||
let assets: MultiAssets = vec![ transferable_reserve_asset ].into();
|
||||
|
||||
let mut executor = new_executor::<T>(trusted_reserve);
|
||||
let instruction = Instruction::ReserveAssetDeposited(assets.clone());
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}: {
|
||||
executor.execute(xcm).map_err(|_| {
|
||||
BenchmarkError::Override(
|
||||
BenchmarkResult::from_weight(T::BlockWeights::get().max_block)
|
||||
)
|
||||
})?;
|
||||
} verify {
|
||||
assert!(executor.holding.ensure_contains(&assets).is_ok());
|
||||
}
|
||||
|
||||
receive_teleported_asset {
|
||||
// If there is no trusted teleporter, then we skip this benchmark.
|
||||
let (trusted_teleporter, teleportable_asset) = T::TrustedTeleporter::get()
|
||||
.ok_or(BenchmarkError::Skip)?;
|
||||
|
||||
if let Some(checked_account) = T::CheckedAccount::get() {
|
||||
if let Some((checked_account, _)) = T::CheckedAccount::get() {
|
||||
T::TransactAsset::mint_into(
|
||||
&checked_account,
|
||||
<
|
||||
@@ -148,18 +153,18 @@ benchmarks_instance_pallet! {
|
||||
let instruction = Instruction::ReceiveTeleportedAsset(assets.clone());
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}: {
|
||||
executor.execute(xcm).map_err(|_| {
|
||||
executor.bench_process(xcm).map_err(|_| {
|
||||
BenchmarkError::Override(
|
||||
BenchmarkResult::from_weight(T::BlockWeights::get().max_block)
|
||||
)
|
||||
})?;
|
||||
} verify {
|
||||
assert!(executor.holding.ensure_contains(&assets).is_ok());
|
||||
assert!(executor.holding().ensure_contains(&assets).is_ok());
|
||||
}
|
||||
|
||||
deposit_asset {
|
||||
let asset = T::get_multi_asset();
|
||||
let mut holding = T::worst_case_holding();
|
||||
let mut holding = T::worst_case_holding(1);
|
||||
|
||||
// Add our asset to the holding.
|
||||
holding.push(asset.clone());
|
||||
@@ -170,15 +175,14 @@ benchmarks_instance_pallet! {
|
||||
assert!(T::TransactAsset::balance(&dest_account).is_zero());
|
||||
|
||||
let mut executor = new_executor::<T>(Default::default());
|
||||
executor.holding = holding.into();
|
||||
executor.set_holding(holding.into());
|
||||
let instruction = Instruction::<XcmCallOf<T>>::DepositAsset {
|
||||
assets: asset.into(),
|
||||
max_assets: 1,
|
||||
beneficiary: dest_location,
|
||||
};
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}: {
|
||||
executor.execute(xcm)?;
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
// dest should have received some asset.
|
||||
assert!(!T::TransactAsset::balance(&dest_account).is_zero())
|
||||
@@ -186,7 +190,7 @@ benchmarks_instance_pallet! {
|
||||
|
||||
deposit_reserve_asset {
|
||||
let asset = T::get_multi_asset();
|
||||
let mut holding = T::worst_case_holding();
|
||||
let mut holding = T::worst_case_holding(1);
|
||||
|
||||
// Add our asset to the holding.
|
||||
holding.push(asset.clone());
|
||||
@@ -197,16 +201,15 @@ benchmarks_instance_pallet! {
|
||||
assert!(T::TransactAsset::balance(&dest_account).is_zero());
|
||||
|
||||
let mut executor = new_executor::<T>(Default::default());
|
||||
executor.holding = holding.into();
|
||||
executor.set_holding(holding.into());
|
||||
let instruction = Instruction::<XcmCallOf<T>>::DepositReserveAsset {
|
||||
assets: asset.into(),
|
||||
max_assets: 1,
|
||||
dest: dest_location,
|
||||
xcm: Xcm::new(),
|
||||
};
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}: {
|
||||
executor.execute(xcm)?;
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
// dest should have received some asset.
|
||||
assert!(!T::TransactAsset::balance(&dest_account).is_zero())
|
||||
@@ -214,16 +217,16 @@ benchmarks_instance_pallet! {
|
||||
|
||||
initiate_teleport {
|
||||
let asset = T::get_multi_asset();
|
||||
let mut holding = T::worst_case_holding();
|
||||
let mut holding = T::worst_case_holding(0);
|
||||
|
||||
// Add our asset to the holding.
|
||||
holding.push(asset.clone());
|
||||
|
||||
// Checked account starts at zero
|
||||
assert!(T::CheckedAccount::get().map_or(true, |c| T::TransactAsset::balance(&c).is_zero()));
|
||||
assert!(T::CheckedAccount::get().map_or(true, |(c, _)| T::TransactAsset::balance(&c).is_zero()));
|
||||
|
||||
let mut executor = new_executor::<T>(Default::default());
|
||||
executor.holding = holding.into();
|
||||
executor.set_holding(holding.into());
|
||||
let instruction = Instruction::<XcmCallOf<T>>::InitiateTeleport {
|
||||
assets: asset.into(),
|
||||
dest: T::valid_destination()?,
|
||||
@@ -231,9 +234,9 @@ benchmarks_instance_pallet! {
|
||||
};
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}: {
|
||||
executor.execute(xcm)?;
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
if let Some(checked_account) = T::CheckedAccount::get() {
|
||||
if let Some((checked_account, _)) = T::CheckedAccount::get() {
|
||||
// teleport checked account should have received some asset.
|
||||
assert!(!T::TransactAsset::balance(&checked_account).is_zero());
|
||||
}
|
||||
|
||||
@@ -18,7 +18,11 @@
|
||||
|
||||
use crate::{fungible as xcm_balances_benchmark, mock::*};
|
||||
use frame_benchmarking::BenchmarkError;
|
||||
use frame_support::{parameter_types, traits::Everything, weights::Weight};
|
||||
use frame_support::{
|
||||
parameter_types,
|
||||
traits::{Everything, Nothing},
|
||||
weights::Weight,
|
||||
};
|
||||
use sp_core::H256;
|
||||
use sp_runtime::{
|
||||
testing::Header,
|
||||
@@ -26,7 +30,7 @@ use sp_runtime::{
|
||||
BuildStorage,
|
||||
};
|
||||
use xcm::latest::prelude::*;
|
||||
use xcm_builder::AllowUnpaidExecutionFrom;
|
||||
use xcm_builder::{AllowUnpaidExecutionFrom, MintLocation};
|
||||
|
||||
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
|
||||
type Block = frame_system::mocking::MockBlock<Test>;
|
||||
@@ -47,9 +51,7 @@ frame_support::construct_runtime!(
|
||||
parameter_types! {
|
||||
pub const BlockHashCount: u64 = 250;
|
||||
pub BlockWeights: frame_system::limits::BlockWeights =
|
||||
frame_system::limits::BlockWeights::simple_max(
|
||||
Weight::from_ref_time(1024).set_proof_size(u64::MAX),
|
||||
);
|
||||
frame_system::limits::BlockWeights::simple_max(Weight::from_parts(1024, u64::MAX));
|
||||
}
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = Everything;
|
||||
@@ -119,13 +121,14 @@ pub type AssetTransactor = xcm_builder::CurrencyAdapter<
|
||||
MatchAnyFungible,
|
||||
AccountIdConverter,
|
||||
u64,
|
||||
CheckedAccount,
|
||||
CheckingAccount,
|
||||
>;
|
||||
|
||||
parameter_types! {
|
||||
/// Maximum number of instructions in a single XCM fragment. A sanity check against weight
|
||||
/// calculations getting too crazy.
|
||||
pub const MaxInstructions: u32 = 100;
|
||||
pub const MaxAssetsIntoHolding: u32 = 64;
|
||||
}
|
||||
|
||||
pub struct XcmConfig;
|
||||
@@ -134,16 +137,25 @@ impl xcm_executor::Config for XcmConfig {
|
||||
type XcmSender = DevNull;
|
||||
type AssetTransactor = AssetTransactor;
|
||||
type OriginConverter = ();
|
||||
type IsReserve = TrustedReserves;
|
||||
type IsReserve = ();
|
||||
type IsTeleporter = TrustedTeleporters;
|
||||
type LocationInverter = xcm_builder::LocationInverter<Ancestry>;
|
||||
type UniversalLocation = UniversalLocation;
|
||||
type Barrier = AllowUnpaidExecutionFrom<Everything>;
|
||||
type Weigher = xcm_builder::FixedWeightBounds<UnitWeightCost, RuntimeCall, MaxInstructions>;
|
||||
type Trader = xcm_builder::FixedRateOfFungible<WeightPrice, ()>;
|
||||
type ResponseHandler = DevNull;
|
||||
type AssetTrap = ();
|
||||
type AssetLocker = ();
|
||||
type AssetExchanger = ();
|
||||
type AssetClaims = ();
|
||||
type SubscriptionService = ();
|
||||
type PalletInstancesInfo = AllPalletsWithSystem;
|
||||
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
|
||||
type FeeManager = ();
|
||||
type MessageExporter = ();
|
||||
type UniversalAliases = Nothing;
|
||||
type CallDispatcher = RuntimeCall;
|
||||
type SafeCallFilter = Everything;
|
||||
}
|
||||
|
||||
impl crate::Config for Test {
|
||||
@@ -151,40 +163,37 @@ impl crate::Config for Test {
|
||||
type AccountIdConverter = AccountIdConverter;
|
||||
fn valid_destination() -> Result<MultiLocation, BenchmarkError> {
|
||||
let valid_destination: MultiLocation =
|
||||
X1(AccountId32 { network: NetworkId::Any, id: [0u8; 32] }).into();
|
||||
X1(AccountId32 { network: None, id: [0u8; 32] }).into();
|
||||
|
||||
Ok(valid_destination)
|
||||
}
|
||||
fn worst_case_holding() -> MultiAssets {
|
||||
crate::mock_worst_case_holding()
|
||||
fn worst_case_holding(depositable_count: u32) -> MultiAssets {
|
||||
crate::mock_worst_case_holding(
|
||||
depositable_count,
|
||||
<XcmConfig as xcm_executor::Config>::MaxAssetsIntoHolding::get(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub type TrustedTeleporters = (xcm_builder::Case<TeleConcreteFung>,);
|
||||
pub type TrustedReserves = (xcm_builder::Case<RsrvConcreteFung>,);
|
||||
pub type TrustedTeleporters = (xcm_builder::Case<TeleportConcreteFungible>,);
|
||||
|
||||
parameter_types! {
|
||||
pub const CheckedAccount: Option<u64> = Some(100);
|
||||
pub const ChildTeleporter: MultiLocation = Parachain(1000).into();
|
||||
pub const CheckingAccount: Option<(u64, MintLocation)> = Some((100, MintLocation::Local));
|
||||
pub const ChildTeleporter: MultiLocation = Parachain(1000).into_location();
|
||||
pub const TrustedTeleporter: Option<(MultiLocation, MultiAsset)> = Some((
|
||||
ChildTeleporter::get(),
|
||||
MultiAsset { id: Concrete(Here.into()), fun: Fungible(100) },
|
||||
MultiAsset { id: Concrete(Here.into_location()), fun: Fungible(100) },
|
||||
));
|
||||
pub const TrustedReserve: Option<(MultiLocation, MultiAsset)> = Some((
|
||||
ChildTeleporter::get(),
|
||||
MultiAsset { id: Concrete(Here.into()), fun: Fungible(100) },
|
||||
));
|
||||
pub const TeleConcreteFung: (MultiAssetFilter, MultiLocation) =
|
||||
(Wild(AllOf { fun: WildFungible, id: Concrete(Here.into()) }), ChildTeleporter::get());
|
||||
pub const RsrvConcreteFung: (MultiAssetFilter, MultiLocation) =
|
||||
(Wild(AllOf { fun: WildFungible, id: Concrete(Here.into()) }), ChildTeleporter::get());
|
||||
pub const TeleportConcreteFungible: (MultiAssetFilter, MultiLocation) =
|
||||
(Wild(AllOf { fun: WildFungible, id: Concrete(Here.into_location()) }), ChildTeleporter::get());
|
||||
pub const ReserveConcreteFungible: (MultiAssetFilter, MultiLocation) =
|
||||
(Wild(AllOf { fun: WildFungible, id: Concrete(Here.into_location()) }), ChildTeleporter::get());
|
||||
}
|
||||
|
||||
impl xcm_balances_benchmark::Config for Test {
|
||||
type TransactAsset = Balances;
|
||||
type CheckedAccount = CheckedAccount;
|
||||
type CheckedAccount = CheckingAccount;
|
||||
type TrustedTeleporter = TrustedTeleporter;
|
||||
type TrustedReserve = TrustedReserve;
|
||||
|
||||
fn get_multi_asset() -> MultiAsset {
|
||||
let amount =
|
||||
|
||||
@@ -34,15 +34,11 @@ pub mod pallet {
|
||||
type TransactAsset: frame_support::traits::fungible::Mutate<Self::AccountId>;
|
||||
|
||||
/// The account used to check assets being teleported.
|
||||
type CheckedAccount: Get<Option<Self::AccountId>>;
|
||||
type CheckedAccount: Get<Option<(Self::AccountId, xcm_builder::MintLocation)>>;
|
||||
|
||||
/// A trusted location which we allow teleports from, and the asset we allow to teleport.
|
||||
type TrustedTeleporter: Get<Option<(xcm::latest::MultiLocation, xcm::latest::MultiAsset)>>;
|
||||
|
||||
/// A trusted location where reserve assets are stored, and the asset we allow to be
|
||||
/// reserves.
|
||||
type TrustedReserve: Get<Option<(xcm::latest::MultiLocation, xcm::latest::MultiAsset)>>;
|
||||
|
||||
/// Give me a fungible asset that your asset transactor is going to accept.
|
||||
fn get_multi_asset() -> xcm::latest::MultiAsset;
|
||||
}
|
||||
|
||||
@@ -20,27 +20,33 @@ use codec::Encode;
|
||||
use frame_benchmarking::{benchmarks, BenchmarkError};
|
||||
use frame_support::dispatch::GetDispatchInfo;
|
||||
use sp_std::vec;
|
||||
use xcm::{latest::prelude::*, DoubleEncoded};
|
||||
use xcm::{
|
||||
latest::{prelude::*, MaybeErrorCode, Weight},
|
||||
DoubleEncoded,
|
||||
};
|
||||
use xcm_executor::{ExecutorError, FeesMode};
|
||||
|
||||
benchmarks! {
|
||||
query_holding {
|
||||
let holding = T::worst_case_holding();
|
||||
report_holding {
|
||||
let holding = T::worst_case_holding(0);
|
||||
|
||||
let mut executor = new_executor::<T>(Default::default());
|
||||
executor.holding = holding.clone().into();
|
||||
executor.set_holding(holding.clone().into());
|
||||
|
||||
let instruction = Instruction::<XcmCallOf<T>>::QueryHolding {
|
||||
query_id: Default::default(),
|
||||
dest: T::valid_destination()?,
|
||||
let instruction = Instruction::<XcmCallOf<T>>::ReportHolding {
|
||||
response_info: QueryResponseInfo {
|
||||
destination: T::valid_destination()?,
|
||||
query_id: Default::default(),
|
||||
max_weight: Weight::MAX,
|
||||
},
|
||||
// Worst case is looking through all holdings for every asset explicitly.
|
||||
assets: Definite(holding),
|
||||
max_response_weight: u64::MAX,
|
||||
};
|
||||
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
|
||||
} : {
|
||||
executor.execute(xcm)?;
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
// The completion of execution above is enough to validate this is completed.
|
||||
}
|
||||
@@ -48,21 +54,21 @@ benchmarks! {
|
||||
// This benchmark does not use any additional orders or instructions. This should be managed
|
||||
// by the `deep` and `shallow` implementation.
|
||||
buy_execution {
|
||||
let holding = T::worst_case_holding().into();
|
||||
let holding = T::worst_case_holding(0).into();
|
||||
|
||||
let mut executor = new_executor::<T>(Default::default());
|
||||
executor.holding = holding;
|
||||
executor.set_holding(holding);
|
||||
|
||||
let fee_asset = Concrete(Here.into());
|
||||
|
||||
let instruction = Instruction::<XcmCallOf<T>>::BuyExecution {
|
||||
fees: (fee_asset, 100_000_000).into(), // should be something inside of holding
|
||||
fees: (fee_asset, 100_000_000u128).into(), // should be something inside of holding
|
||||
weight_limit: WeightLimit::Unlimited,
|
||||
};
|
||||
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
} : {
|
||||
executor.execute(xcm)?;
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
|
||||
}
|
||||
@@ -70,11 +76,12 @@ benchmarks! {
|
||||
query_response {
|
||||
let mut executor = new_executor::<T>(Default::default());
|
||||
let (query_id, response) = T::worst_case_response();
|
||||
let max_weight = u64::MAX;
|
||||
let instruction = Instruction::QueryResponse { query_id, response, max_weight };
|
||||
let max_weight = Weight::MAX;
|
||||
let querier: Option<MultiLocation> = Some(Here.into());
|
||||
let instruction = Instruction::QueryResponse { query_id, response, max_weight, querier };
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}: {
|
||||
executor.execute(xcm)?;
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
// The assert above is enough to show this XCM succeeded
|
||||
}
|
||||
@@ -83,43 +90,38 @@ benchmarks! {
|
||||
// and included in the final weight calculation. So this is just the overhead of submitting
|
||||
// a noop call.
|
||||
transact {
|
||||
let origin = T::transact_origin()?;
|
||||
let (origin, noop_call) = T::transact_origin_and_runtime_call()?;
|
||||
let mut executor = new_executor::<T>(origin);
|
||||
let noop_call: <T as Config>::RuntimeCall = frame_system::Call::remark_with_event {
|
||||
remark: Default::default()
|
||||
}.into();
|
||||
let double_encoded_noop_call: DoubleEncoded<_> = noop_call.encode().into();
|
||||
|
||||
let instruction = Instruction::Transact {
|
||||
origin_type: OriginKind::SovereignAccount,
|
||||
require_weight_at_most: noop_call.get_dispatch_info().weight.ref_time(),
|
||||
origin_kind: OriginKind::SovereignAccount,
|
||||
require_weight_at_most: noop_call.get_dispatch_info().weight,
|
||||
call: double_encoded_noop_call,
|
||||
};
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
|
||||
let num_events = frame_system::Pallet::<T>::events().len();
|
||||
}: {
|
||||
executor.execute(xcm)?;
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
// TODO make better assertion? #4426
|
||||
let num_events2 = frame_system::Pallet::<T>::events().len();
|
||||
assert_eq!(num_events + 1, num_events2);
|
||||
// TODO Make the assertion configurable?
|
||||
}
|
||||
|
||||
refund_surplus {
|
||||
let holding = T::worst_case_holding().into();
|
||||
let holding = T::worst_case_holding(0).into();
|
||||
let mut executor = new_executor::<T>(Default::default());
|
||||
executor.holding = holding;
|
||||
executor.total_surplus = 1337;
|
||||
executor.total_refunded = 0;
|
||||
executor.set_holding(holding);
|
||||
executor.set_total_surplus(Weight::from_parts(1337, 1337));
|
||||
executor.set_total_refunded(Weight::zero());
|
||||
|
||||
let instruction = Instruction::<XcmCallOf<T>>::RefundSurplus;
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
} : {
|
||||
let result = executor.execute(xcm)?;
|
||||
let result = executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
assert_eq!(executor.total_surplus, 1337);
|
||||
assert_eq!(executor.total_refunded, 1337);
|
||||
assert_eq!(executor.total_surplus(), &Weight::from_parts(1337, 1337));
|
||||
assert_eq!(executor.total_refunded(), &Weight::from_parts(1337, 1337));
|
||||
}
|
||||
|
||||
set_error_handler {
|
||||
@@ -127,9 +129,9 @@ benchmarks! {
|
||||
let instruction = Instruction::<XcmCallOf<T>>::SetErrorHandler(Xcm(vec![]));
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
} : {
|
||||
executor.execute(xcm)?;
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
assert_eq!(executor.error_handler, Xcm(vec![]));
|
||||
assert_eq!(executor.error_handler(), &Xcm(vec![]));
|
||||
}
|
||||
|
||||
set_appendix {
|
||||
@@ -138,20 +140,20 @@ benchmarks! {
|
||||
let instruction = Instruction::<XcmCallOf<T>>::SetAppendix(appendix);
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
} : {
|
||||
executor.execute(xcm)?;
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
assert_eq!(executor.appendix, Xcm(vec![]));
|
||||
assert_eq!(executor.appendix(), &Xcm(vec![]));
|
||||
}
|
||||
|
||||
clear_error {
|
||||
let mut executor = new_executor::<T>(Default::default());
|
||||
executor.error = Some((5u32, XcmError::Overflow));
|
||||
executor.set_error(Some((5u32, XcmError::Overflow)));
|
||||
let instruction = Instruction::<XcmCallOf<T>>::ClearError;
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
} : {
|
||||
executor.execute(xcm)?;
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
assert!(executor.error.is_none())
|
||||
assert!(executor.error().is_none())
|
||||
}
|
||||
|
||||
descend_origin {
|
||||
@@ -160,11 +162,11 @@ benchmarks! {
|
||||
let instruction = Instruction::DescendOrigin(who.clone());
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
} : {
|
||||
executor.execute(xcm)?;
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
assert_eq!(
|
||||
executor.origin,
|
||||
Some(MultiLocation {
|
||||
executor.origin(),
|
||||
&Some(MultiLocation {
|
||||
parents: 0,
|
||||
interior: who,
|
||||
}),
|
||||
@@ -176,22 +178,24 @@ benchmarks! {
|
||||
let instruction = Instruction::ClearOrigin;
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
} : {
|
||||
executor.execute(xcm)?;
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
assert_eq!(executor.origin, None);
|
||||
assert_eq!(executor.origin(), &None);
|
||||
}
|
||||
|
||||
report_error {
|
||||
let mut executor = new_executor::<T>(Default::default());
|
||||
executor.error = Some((0u32, XcmError::Unimplemented));
|
||||
executor.set_error(Some((0u32, XcmError::Unimplemented)));
|
||||
let query_id = Default::default();
|
||||
let dest = T::valid_destination().map_err(|_| BenchmarkError::Skip)?;
|
||||
let max_response_weight = Default::default();
|
||||
let destination = T::valid_destination().map_err(|_| BenchmarkError::Skip)?;
|
||||
let max_weight = Default::default();
|
||||
|
||||
let instruction = Instruction::ReportError { query_id, dest, max_response_weight };
|
||||
let instruction = Instruction::ReportError(QueryResponseInfo {
|
||||
query_id, destination, max_weight
|
||||
});
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}: {
|
||||
executor.execute(xcm)?;
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
// the execution succeeding is all we need to verify this xcm was successful
|
||||
}
|
||||
@@ -205,6 +209,11 @@ benchmarks! {
|
||||
<T::XcmConfig as xcm_executor::Config>::AssetTrap::drop_assets(
|
||||
&origin,
|
||||
assets.clone().into(),
|
||||
&XcmContext {
|
||||
origin: Some(origin.clone()),
|
||||
message_hash: [0; 32],
|
||||
topic: None,
|
||||
},
|
||||
);
|
||||
|
||||
// Assets should be in the trap now.
|
||||
@@ -213,9 +222,9 @@ benchmarks! {
|
||||
let instruction = Instruction::ClaimAsset { assets: assets.clone(), ticket };
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
} :{
|
||||
executor.execute(xcm)?;
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
assert!(executor.holding.ensure_contains(&assets).is_ok());
|
||||
assert!(executor.holding().ensure_contains(&assets).is_ok());
|
||||
}
|
||||
|
||||
trap {
|
||||
@@ -225,14 +234,12 @@ benchmarks! {
|
||||
// In order to access result in the verification below, it needs to be defined here.
|
||||
let mut _result = Ok(());
|
||||
} : {
|
||||
_result = executor.execute(xcm);
|
||||
_result = executor.bench_process(xcm);
|
||||
} verify {
|
||||
match _result {
|
||||
Err(error) if error.xcm_error == XcmError::Trap(10) => {
|
||||
// This is the success condition
|
||||
},
|
||||
_ => Err("xcm trap did not return the expected error")?
|
||||
};
|
||||
assert!(matches!(_result, Err(ExecutorError {
|
||||
xcm_error: XcmError::Trap(10),
|
||||
..
|
||||
})));
|
||||
}
|
||||
|
||||
subscribe_version {
|
||||
@@ -244,7 +251,7 @@ benchmarks! {
|
||||
let instruction = Instruction::SubscribeVersion { query_id, max_response_weight };
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
} : {
|
||||
executor.execute(xcm)?;
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
assert!(<T::XcmConfig as xcm_executor::Config>::SubscriptionService::is_subscribed(&origin));
|
||||
}
|
||||
@@ -252,13 +259,18 @@ benchmarks! {
|
||||
unsubscribe_version {
|
||||
use xcm_executor::traits::VersionChangeNotifier;
|
||||
// First we need to subscribe to notifications.
|
||||
let origin = T::transact_origin()?;
|
||||
let (origin, _) = T::transact_origin_and_runtime_call()?;
|
||||
let query_id = Default::default();
|
||||
let max_response_weight = Default::default();
|
||||
<T::XcmConfig as xcm_executor::Config>::SubscriptionService::start(
|
||||
&origin,
|
||||
query_id,
|
||||
max_response_weight
|
||||
max_response_weight,
|
||||
&XcmContext {
|
||||
origin: Some(origin.clone()),
|
||||
message_hash: [0; 32],
|
||||
topic: None,
|
||||
},
|
||||
).map_err(|_| "Could not start subscription")?;
|
||||
assert!(<T::XcmConfig as xcm_executor::Config>::SubscriptionService::is_subscribed(&origin));
|
||||
|
||||
@@ -266,30 +278,330 @@ benchmarks! {
|
||||
let instruction = Instruction::UnsubscribeVersion;
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
} : {
|
||||
executor.execute(xcm)?;
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
assert!(!<T::XcmConfig as xcm_executor::Config>::SubscriptionService::is_subscribed(&origin));
|
||||
}
|
||||
|
||||
initiate_reserve_withdraw {
|
||||
let holding = T::worst_case_holding();
|
||||
let holding = T::worst_case_holding(1);
|
||||
let assets_filter = MultiAssetFilter::Definite(holding.clone());
|
||||
let reserve = T::valid_destination().map_err(|_| BenchmarkError::Skip)?;
|
||||
let mut executor = new_executor::<T>(Default::default());
|
||||
executor.holding = holding.into();
|
||||
executor.set_holding(holding.into());
|
||||
let instruction = Instruction::InitiateReserveWithdraw { assets: assets_filter, reserve, xcm: Xcm(vec![]) };
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}:{
|
||||
executor.execute(xcm)?;
|
||||
}: {
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
// The execute completing successfully is as good as we can check.
|
||||
// TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426
|
||||
}
|
||||
|
||||
burn_asset {
|
||||
let holding = T::worst_case_holding(0);
|
||||
let assets = holding.clone();
|
||||
|
||||
let mut executor = new_executor::<T>(Default::default());
|
||||
executor.set_holding(holding.into());
|
||||
|
||||
let instruction = Instruction::BurnAsset(assets.into());
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}: {
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
assert!(executor.holding().is_empty());
|
||||
}
|
||||
|
||||
expect_asset {
|
||||
let holding = T::worst_case_holding(0);
|
||||
let assets = holding.clone();
|
||||
|
||||
let mut executor = new_executor::<T>(Default::default());
|
||||
executor.set_holding(holding.into());
|
||||
|
||||
let instruction = Instruction::ExpectAsset(assets.into());
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}: {
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
// `execute` completing successfully is as good as we can check.
|
||||
}
|
||||
|
||||
expect_origin {
|
||||
let expected_origin = Parent.into();
|
||||
let mut executor = new_executor::<T>(Default::default());
|
||||
|
||||
let instruction = Instruction::ExpectOrigin(Some(expected_origin));
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
let mut _result = Ok(());
|
||||
}: {
|
||||
_result = executor.bench_process(xcm);
|
||||
} verify {
|
||||
assert!(matches!(_result, Err(ExecutorError {
|
||||
xcm_error: XcmError::ExpectationFalse,
|
||||
..
|
||||
})));
|
||||
}
|
||||
|
||||
expect_error {
|
||||
let mut executor = new_executor::<T>(Default::default());
|
||||
executor.set_error(Some((3u32, XcmError::Overflow)));
|
||||
|
||||
let instruction = Instruction::ExpectError(None);
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
let mut _result = Ok(());
|
||||
}: {
|
||||
_result = executor.bench_process(xcm);
|
||||
} verify {
|
||||
assert!(matches!(_result, Err(ExecutorError {
|
||||
xcm_error: XcmError::ExpectationFalse,
|
||||
..
|
||||
})));
|
||||
}
|
||||
|
||||
query_pallet {
|
||||
let query_id = Default::default();
|
||||
let destination = T::valid_destination().map_err(|_| BenchmarkError::Skip)?;
|
||||
let max_weight = Default::default();
|
||||
let mut executor = new_executor::<T>(Default::default());
|
||||
|
||||
let instruction = Instruction::QueryPallet {
|
||||
module_name: b"frame_system".to_vec(),
|
||||
response_info: QueryResponseInfo { destination, query_id, max_weight },
|
||||
};
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}: {
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
// TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426
|
||||
}
|
||||
|
||||
expect_pallet {
|
||||
let mut executor = new_executor::<T>(Default::default());
|
||||
|
||||
let instruction = Instruction::ExpectPallet {
|
||||
index: 0,
|
||||
name: b"System".to_vec(),
|
||||
module_name: b"frame_system".to_vec(),
|
||||
crate_major: 4,
|
||||
min_crate_minor: 0,
|
||||
};
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}: {
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
// the execution succeeding is all we need to verify this xcm was successful
|
||||
}
|
||||
|
||||
report_transact_status {
|
||||
let query_id = Default::default();
|
||||
let destination = T::valid_destination().map_err(|_| BenchmarkError::Skip)?;
|
||||
let max_weight = Default::default();
|
||||
|
||||
let mut executor = new_executor::<T>(Default::default());
|
||||
executor.set_transact_status(b"MyError".to_vec().into());
|
||||
|
||||
let instruction = Instruction::ReportTransactStatus(QueryResponseInfo {
|
||||
query_id,
|
||||
destination,
|
||||
max_weight,
|
||||
});
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}: {
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
// TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426
|
||||
}
|
||||
|
||||
clear_transact_status {
|
||||
let mut executor = new_executor::<T>(Default::default());
|
||||
executor.set_transact_status(MaybeErrorCode::Error(b"MyError".to_vec()));
|
||||
|
||||
let instruction = Instruction::ClearTransactStatus;
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}: {
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
assert_eq!(executor.transact_status(), &MaybeErrorCode::Success);
|
||||
}
|
||||
|
||||
set_topic {
|
||||
let mut executor = new_executor::<T>(Default::default());
|
||||
|
||||
let instruction = Instruction::SetTopic([1; 32]);
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}: {
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
assert_eq!(executor.topic(), &Some([1; 32]));
|
||||
}
|
||||
|
||||
clear_topic {
|
||||
let mut executor = new_executor::<T>(Default::default());
|
||||
executor.set_topic(Some([2; 32]));
|
||||
|
||||
let instruction = Instruction::ClearTopic;
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}: {
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
assert_eq!(executor.topic(), &None);
|
||||
}
|
||||
|
||||
exchange_asset {
|
||||
let (give, want) = T::worst_case_asset_exchange().map_err(|_| BenchmarkError::Skip)?;
|
||||
let assets = give.clone();
|
||||
|
||||
let mut executor = new_executor::<T>(Default::default());
|
||||
executor.set_holding(give.into());
|
||||
let instruction = Instruction::ExchangeAsset {
|
||||
give: assets.into(),
|
||||
want: want.clone(),
|
||||
maximal: true,
|
||||
};
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}: {
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
assert_eq!(executor.holding(), &want.into());
|
||||
}
|
||||
|
||||
universal_origin {
|
||||
let alias = T::universal_alias().map_err(|_| BenchmarkError::Skip)?;
|
||||
|
||||
let mut executor = new_executor::<T>(Here.into_location());
|
||||
|
||||
let instruction = Instruction::UniversalOrigin(alias.clone());
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}: {
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
use frame_support::traits::Get;
|
||||
let universal_location = <T::XcmConfig as xcm_executor::Config>::UniversalLocation::get();
|
||||
assert_eq!(executor.origin(), &Some(X1(alias).relative_to(&universal_location)));
|
||||
}
|
||||
|
||||
set_fees_mode {
|
||||
let mut executor = new_executor::<T>(Default::default());
|
||||
executor.set_fees_mode(FeesMode { jit_withdraw: false });
|
||||
|
||||
let instruction = Instruction::SetFeesMode { jit_withdraw: true };
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}: {
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
assert_eq!(executor.fees_mode(), &FeesMode { jit_withdraw: true });
|
||||
}
|
||||
|
||||
lock_asset {
|
||||
let (unlocker, owner, asset) = T::unlockable_asset()?;
|
||||
|
||||
let mut executor = new_executor::<T>(owner);
|
||||
executor.set_holding(asset.clone().into());
|
||||
|
||||
let instruction = Instruction::LockAsset { asset, unlocker };
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}: {
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
// TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426
|
||||
}
|
||||
|
||||
unlock_asset {
|
||||
use xcm_executor::traits::{AssetLock, Enact};
|
||||
|
||||
let (unlocker, owner, asset) = T::unlockable_asset()?;
|
||||
|
||||
let mut executor = new_executor::<T>(unlocker.clone());
|
||||
|
||||
// We first place the asset in lock first...
|
||||
<T::XcmConfig as xcm_executor::Config>::AssetLocker::prepare_lock(
|
||||
unlocker,
|
||||
asset.clone(),
|
||||
owner.clone(),
|
||||
)
|
||||
.map_err(|_| BenchmarkError::Skip)?
|
||||
.enact()
|
||||
.map_err(|_| BenchmarkError::Skip)?;
|
||||
|
||||
// ... then unlock them with the UnlockAsset instruction.
|
||||
let instruction = Instruction::UnlockAsset { asset, target: owner };
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}: {
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
|
||||
}
|
||||
|
||||
note_unlockable {
|
||||
use xcm_executor::traits::{AssetLock, Enact};
|
||||
|
||||
let (unlocker, owner, asset) = T::unlockable_asset()?;
|
||||
|
||||
let mut executor = new_executor::<T>(unlocker.clone());
|
||||
|
||||
// We first place the asset in lock first...
|
||||
<T::XcmConfig as xcm_executor::Config>::AssetLocker::prepare_lock(
|
||||
unlocker,
|
||||
asset.clone(),
|
||||
owner.clone(),
|
||||
)
|
||||
.map_err(|_| BenchmarkError::Skip)?
|
||||
.enact()
|
||||
.map_err(|_| BenchmarkError::Skip)?;
|
||||
|
||||
// ... then note them as unlockable with the NoteUnlockable instruction.
|
||||
let instruction = Instruction::NoteUnlockable { asset, owner };
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}: {
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
|
||||
}
|
||||
|
||||
request_unlock {
|
||||
use xcm_executor::traits::{AssetLock, Enact};
|
||||
|
||||
let (locker, owner, asset) = T::unlockable_asset()?;
|
||||
|
||||
// We first place the asset in lock first...
|
||||
<T::XcmConfig as xcm_executor::Config>::AssetLocker::prepare_lock(
|
||||
locker.clone(),
|
||||
asset.clone(),
|
||||
owner.clone(),
|
||||
)
|
||||
.map_err(|_| BenchmarkError::Skip)?
|
||||
.enact()
|
||||
.map_err(|_| BenchmarkError::Skip)?;
|
||||
|
||||
// ... then request for an unlock with the RequestUnlock instruction.
|
||||
let mut executor = new_executor::<T>(owner);
|
||||
let instruction = Instruction::RequestUnlock { asset, locker };
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}: {
|
||||
executor.bench_process(xcm)?;
|
||||
} verify {
|
||||
// TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426
|
||||
}
|
||||
|
||||
unpaid_execution {
|
||||
let mut executor = new_executor::<T>(Default::default());
|
||||
executor.set_origin(Some(Here.into()));
|
||||
|
||||
let instruction = Instruction::<XcmCallOf<T>>::UnpaidExecution {
|
||||
weight_limit: WeightLimit::Unlimited,
|
||||
check_origin: Some(Here.into()),
|
||||
};
|
||||
|
||||
let xcm = Xcm(vec![instruction]);
|
||||
}: {
|
||||
executor.bench_process(xcm)?;
|
||||
}
|
||||
|
||||
impl_benchmark_test_suite!(
|
||||
Pallet,
|
||||
crate::generic::mock::new_test_ext(),
|
||||
crate::generic::mock::Test
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@@ -30,7 +30,10 @@ use sp_runtime::{
|
||||
BuildStorage,
|
||||
};
|
||||
use xcm_builder::{
|
||||
test_utils::{Assets, TestAssetTrap, TestSubscriptionService},
|
||||
test_utils::{
|
||||
Assets, TestAssetExchanger, TestAssetLocker, TestAssetTrap, TestSubscriptionService,
|
||||
TestUniversalAliases,
|
||||
},
|
||||
AllowUnpaidExecutionFrom,
|
||||
};
|
||||
use xcm_executor::traits::ConvertOrigin;
|
||||
@@ -52,9 +55,7 @@ frame_support::construct_runtime!(
|
||||
parameter_types! {
|
||||
pub const BlockHashCount: u64 = 250;
|
||||
pub BlockWeights: frame_system::limits::BlockWeights =
|
||||
frame_system::limits::BlockWeights::simple_max(
|
||||
Weight::from_ref_time(1024).set_proof_size(u64::MAX),
|
||||
);
|
||||
frame_system::limits::BlockWeights::simple_max(Weight::from_parts(1024, u64::MAX));
|
||||
}
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
@@ -87,17 +88,22 @@ impl frame_system::Config for Test {
|
||||
/// The benchmarks in this pallet should never need an asset transactor to begin with.
|
||||
pub struct NoAssetTransactor;
|
||||
impl xcm_executor::traits::TransactAsset for NoAssetTransactor {
|
||||
fn deposit_asset(_: &MultiAsset, _: &MultiLocation) -> Result<(), XcmError> {
|
||||
fn deposit_asset(_: &MultiAsset, _: &MultiLocation, _: &XcmContext) -> Result<(), XcmError> {
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
fn withdraw_asset(_: &MultiAsset, _: &MultiLocation) -> Result<Assets, XcmError> {
|
||||
fn withdraw_asset(
|
||||
_: &MultiAsset,
|
||||
_: &MultiLocation,
|
||||
_: Option<&XcmContext>,
|
||||
) -> Result<Assets, XcmError> {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const MaxInstructions: u32 = 100;
|
||||
pub const MaxAssetsIntoHolding: u32 = 64;
|
||||
}
|
||||
|
||||
pub struct XcmConfig;
|
||||
@@ -108,14 +114,24 @@ impl xcm_executor::Config for XcmConfig {
|
||||
type OriginConverter = AlwaysSignedByDefault<RuntimeOrigin>;
|
||||
type IsReserve = AllAssetLocationsPass;
|
||||
type IsTeleporter = ();
|
||||
type LocationInverter = xcm_builder::LocationInverter<Ancestry>;
|
||||
type UniversalLocation = UniversalLocation;
|
||||
type Barrier = AllowUnpaidExecutionFrom<Everything>;
|
||||
type Weigher = xcm_builder::FixedWeightBounds<UnitWeightCost, RuntimeCall, MaxInstructions>;
|
||||
type Trader = xcm_builder::FixedRateOfFungible<WeightPrice, ()>;
|
||||
type ResponseHandler = DevNull;
|
||||
type AssetTrap = TestAssetTrap;
|
||||
type AssetLocker = TestAssetLocker;
|
||||
type AssetExchanger = TestAssetExchanger;
|
||||
type AssetClaims = TestAssetTrap;
|
||||
type SubscriptionService = TestSubscriptionService;
|
||||
type PalletInstancesInfo = AllPalletsWithSystem;
|
||||
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
|
||||
type FeeManager = ();
|
||||
// No bridges yet...
|
||||
type MessageExporter = ();
|
||||
type UniversalAliases = TestUniversalAliases;
|
||||
type CallDispatcher = RuntimeCall;
|
||||
type SafeCallFilter = Everything;
|
||||
}
|
||||
|
||||
impl crate::Config for Test {
|
||||
@@ -123,12 +139,15 @@ impl crate::Config for Test {
|
||||
type AccountIdConverter = AccountIdConverter;
|
||||
fn valid_destination() -> Result<MultiLocation, BenchmarkError> {
|
||||
let valid_destination: MultiLocation =
|
||||
Junction::AccountId32 { network: NetworkId::Any, id: [0u8; 32] }.into();
|
||||
Junction::AccountId32 { network: None, id: [0u8; 32] }.into();
|
||||
|
||||
Ok(valid_destination)
|
||||
}
|
||||
fn worst_case_holding() -> MultiAssets {
|
||||
crate::mock_worst_case_holding()
|
||||
fn worst_case_holding(depositable_count: u32) -> MultiAssets {
|
||||
crate::mock_worst_case_holding(
|
||||
depositable_count,
|
||||
<XcmConfig as xcm_executor::Config>::MaxAssetsIntoHolding::get(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,10 +159,19 @@ impl generic::Config for Test {
|
||||
(0, Response::Assets(assets))
|
||||
}
|
||||
|
||||
fn transact_origin() -> Result<MultiLocation, BenchmarkError> {
|
||||
fn worst_case_asset_exchange() -> Result<(MultiAssets, MultiAssets), BenchmarkError> {
|
||||
Ok(Default::default())
|
||||
}
|
||||
|
||||
fn universal_alias() -> Result<Junction, BenchmarkError> {
|
||||
Ok(GlobalConsensus(ByGenesis([0; 32])))
|
||||
}
|
||||
|
||||
fn transact_origin_and_runtime_call(
|
||||
) -> Result<(MultiLocation, <Self as generic::Config>::RuntimeCall), BenchmarkError> {
|
||||
Ok((Default::default(), frame_system::Call::remark_with_event { remark: vec![] }.into()))
|
||||
}
|
||||
|
||||
fn subscribe_origin() -> Result<MultiLocation, BenchmarkError> {
|
||||
Ok(Default::default())
|
||||
}
|
||||
@@ -153,6 +181,11 @@ impl generic::Config for Test {
|
||||
let ticket = MultiLocation { parents: 0, interior: X1(GeneralIndex(0)) };
|
||||
Ok((Default::default(), ticket, assets))
|
||||
}
|
||||
|
||||
fn unlockable_asset() -> Result<(MultiLocation, MultiLocation, MultiAsset), BenchmarkError> {
|
||||
let assets: MultiAsset = (Concrete(Here.into()), 100).into();
|
||||
Ok((Default::default(), Default::default(), assets))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_test_ext() -> sp_io::TestExternalities {
|
||||
|
||||
@@ -12,7 +12,7 @@ pub mod pallet {
|
||||
dispatch::{Dispatchable, GetDispatchInfo},
|
||||
pallet_prelude::Encode,
|
||||
};
|
||||
use xcm::latest::{MultiAssets, MultiLocation, Response};
|
||||
use xcm::latest::{Junction, MultiAsset, MultiAssets, MultiLocation, Response};
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config<I: 'static = ()>: frame_system::Config + crate::Config {
|
||||
@@ -24,18 +24,37 @@ pub mod pallet {
|
||||
/// The response which causes the most runtime weight.
|
||||
fn worst_case_response() -> (u64, Response);
|
||||
|
||||
/// The `MultiLocation` used for successful transaction XCMs.
|
||||
/// The pair of asset collections which causes the most runtime weight if demanded to be
|
||||
/// exchanged.
|
||||
///
|
||||
/// If set to `None`, benchmarks which rely on a `transact_origin` will be skipped.
|
||||
fn transact_origin() -> Result<MultiLocation, BenchmarkError>;
|
||||
/// The first element in the returned tuple represents the assets that are being exchanged
|
||||
/// from, whereas the second element represents the assets that are being exchanged to.
|
||||
///
|
||||
/// If set to `Err`, benchmarks which rely on an `exchange_asset` will be skipped.
|
||||
fn worst_case_asset_exchange() -> Result<(MultiAssets, MultiAssets), BenchmarkError>;
|
||||
|
||||
/// A `Junction` that is one of the `UniversalAliases` configured by the XCM executor.
|
||||
///
|
||||
/// If set to `Err`, benchmarks which rely on a universal alias will be skipped.
|
||||
fn universal_alias() -> Result<Junction, BenchmarkError>;
|
||||
|
||||
/// The `MultiLocation` and `RuntimeCall` used for successful transaction XCMs.
|
||||
///
|
||||
/// If set to `Err`, benchmarks which rely on a `transact_origin_and_runtime_call` will be
|
||||
/// skipped.
|
||||
fn transact_origin_and_runtime_call(
|
||||
) -> Result<(MultiLocation, <Self as crate::generic::Config<I>>::RuntimeCall), BenchmarkError>;
|
||||
|
||||
/// A valid `MultiLocation` we can successfully subscribe to.
|
||||
///
|
||||
/// If set to `None`, benchmarks which rely on a `subscribe_origin` will be skipped.
|
||||
/// If set to `Err`, benchmarks which rely on a `subscribe_origin` will be skipped.
|
||||
fn subscribe_origin() -> Result<MultiLocation, BenchmarkError>;
|
||||
|
||||
/// Return an origin, ticket, and assets that can be trapped and claimed.
|
||||
fn claimable_asset() -> Result<(MultiLocation, MultiLocation, MultiAssets), BenchmarkError>;
|
||||
|
||||
/// Return an unlocker, owner and assets that can be locked and unlocked.
|
||||
fn unlockable_asset() -> Result<(MultiLocation, MultiLocation, MultiAsset), BenchmarkError>;
|
||||
}
|
||||
|
||||
#[pallet::pallet]
|
||||
|
||||
@@ -22,7 +22,7 @@ use codec::Encode;
|
||||
use frame_benchmarking::{account, BenchmarkError};
|
||||
use sp_std::prelude::*;
|
||||
use xcm::latest::prelude::*;
|
||||
use xcm_executor::traits::Convert;
|
||||
use xcm_executor::{traits::Convert, Config as XcmConfig};
|
||||
|
||||
pub mod fungible;
|
||||
pub mod generic;
|
||||
@@ -36,7 +36,7 @@ pub trait Config: frame_system::Config {
|
||||
///
|
||||
/// These might affect the execution of XCM messages, such as defining how the
|
||||
/// `TransactAsset` is implemented.
|
||||
type XcmConfig: xcm_executor::Config;
|
||||
type XcmConfig: XcmConfig;
|
||||
|
||||
/// A converter between a multi-location to a sovereign account.
|
||||
type AccountIdConverter: Convert<MultiLocation, Self::AccountId>;
|
||||
@@ -46,7 +46,7 @@ pub trait Config: frame_system::Config {
|
||||
fn valid_destination() -> Result<MultiLocation, BenchmarkError>;
|
||||
|
||||
/// Worst case scenario for a holding account in this runtime.
|
||||
fn worst_case_holding() -> MultiAssets;
|
||||
fn worst_case_holding(depositable_count: u32) -> MultiAssets;
|
||||
}
|
||||
|
||||
const SEED: u32 = 0;
|
||||
@@ -56,15 +56,15 @@ pub type ExecutorOf<T> = xcm_executor::XcmExecutor<<T as Config>::XcmConfig>;
|
||||
/// The overarching call type.
|
||||
pub type OverArchingCallOf<T> = <T as frame_system::Config>::RuntimeCall;
|
||||
/// The asset transactor of our executor
|
||||
pub type AssetTransactorOf<T> = <<T as Config>::XcmConfig as xcm_executor::Config>::AssetTransactor;
|
||||
pub type AssetTransactorOf<T> = <<T as Config>::XcmConfig as XcmConfig>::AssetTransactor;
|
||||
/// The call type of executor's config. Should eventually resolve to the same overarching call type.
|
||||
pub type XcmCallOf<T> = <<T as Config>::XcmConfig as xcm_executor::Config>::RuntimeCall;
|
||||
pub type XcmCallOf<T> = <<T as Config>::XcmConfig as XcmConfig>::RuntimeCall;
|
||||
|
||||
pub fn mock_worst_case_holding() -> MultiAssets {
|
||||
const HOLDING_FUNGIBLES: u32 = 99;
|
||||
const HOLDING_NON_FUNGIBLES: u32 = 99;
|
||||
pub fn mock_worst_case_holding(depositable_count: u32, max_assets: u32) -> MultiAssets {
|
||||
let fungibles_amount: u128 = 100;
|
||||
(0..HOLDING_FUNGIBLES)
|
||||
let holding_fungibles = max_assets / 2 - depositable_count;
|
||||
let holding_non_fungibles = holding_fungibles;
|
||||
(0..holding_fungibles)
|
||||
.map(|i| {
|
||||
MultiAsset {
|
||||
id: Concrete(GeneralIndex(i as u128).into()),
|
||||
@@ -73,7 +73,7 @@ pub fn mock_worst_case_holding() -> MultiAssets {
|
||||
.into()
|
||||
})
|
||||
.chain(core::iter::once(MultiAsset { id: Concrete(Here.into()), fun: Fungible(u128::MAX) }))
|
||||
.chain((0..HOLDING_NON_FUNGIBLES).map(|i| MultiAsset {
|
||||
.chain((0..holding_non_fungibles).map(|i| MultiAsset {
|
||||
id: Concrete(GeneralIndex(i as u128).into()),
|
||||
fun: NonFungible(asset_instance_from(i)),
|
||||
}))
|
||||
@@ -89,7 +89,7 @@ pub fn asset_instance_from(x: u32) -> AssetInstance {
|
||||
}
|
||||
|
||||
pub fn new_executor<T: Config>(origin: MultiLocation) -> ExecutorOf<T> {
|
||||
ExecutorOf::<T>::new(origin)
|
||||
ExecutorOf::<T>::new(origin, [0; 32])
|
||||
}
|
||||
|
||||
/// Build a multi-location from an account id.
|
||||
@@ -99,7 +99,7 @@ fn account_id_junction<T: frame_system::Config>(index: u32) -> Junction {
|
||||
encoded.resize(32, 0u8);
|
||||
let mut id = [0u8; 32];
|
||||
id.copy_from_slice(&encoded);
|
||||
Junction::AccountId32 { network: NetworkId::Any, id }
|
||||
Junction::AccountId32 { network: None, id }
|
||||
}
|
||||
|
||||
pub fn account_and_location<T: Config>(index: u32) -> (T::AccountId, MultiLocation) {
|
||||
|
||||
@@ -15,24 +15,34 @@
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::*;
|
||||
use frame_support::parameter_types;
|
||||
use xcm::latest::Weight as XCMWeight;
|
||||
use xcm_executor::traits::FilterAssetLocation;
|
||||
use frame_support::{parameter_types, traits::ContainsPair};
|
||||
use xcm::latest::Weight;
|
||||
|
||||
// An xcm sender/receiver akin to > /dev/null
|
||||
pub struct DevNull;
|
||||
impl xcm::opaque::latest::SendXcm for DevNull {
|
||||
fn send_xcm(_: impl Into<MultiLocation>, _: Xcm<()>) -> SendResult {
|
||||
Ok(())
|
||||
type Ticket = ();
|
||||
fn validate(_: &mut Option<MultiLocation>, _: &mut Option<Xcm<()>>) -> SendResult<()> {
|
||||
Ok(((), MultiAssets::new()))
|
||||
}
|
||||
fn deliver(_: ()) -> Result<XcmHash, SendError> {
|
||||
Ok([0; 32])
|
||||
}
|
||||
}
|
||||
|
||||
impl xcm_executor::traits::OnResponse for DevNull {
|
||||
fn expecting_response(_: &MultiLocation, _: u64) -> bool {
|
||||
fn expecting_response(_: &MultiLocation, _: u64, _: Option<&MultiLocation>) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_response(_: &MultiLocation, _: u64, _: Response, _: XCMWeight) -> XCMWeight {
|
||||
0
|
||||
fn on_response(
|
||||
_: &MultiLocation,
|
||||
_: u64,
|
||||
_: Option<&MultiLocation>,
|
||||
_: Response,
|
||||
_: Weight,
|
||||
_: &XcmContext,
|
||||
) -> Weight {
|
||||
Weight::zero()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,14 +62,14 @@ impl xcm_executor::traits::Convert<MultiLocation, u64> for AccountIdConverter {
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub Ancestry: MultiLocation = Junction::Parachain(101).into();
|
||||
pub UnitWeightCost: u64 = 10;
|
||||
pub WeightPrice: (AssetId, u128) = (Concrete(Here.into()), 1_000_000);
|
||||
pub UniversalLocation: InteriorMultiLocation = Junction::Parachain(101).into();
|
||||
pub UnitWeightCost: Weight = Weight::from_parts(10, 10);
|
||||
pub WeightPrice: (AssetId, u128, u128) = (Concrete(Here.into()), 1_000_000, 1024);
|
||||
}
|
||||
|
||||
pub struct AllAssetLocationsPass;
|
||||
impl FilterAssetLocation for AllAssetLocationsPass {
|
||||
fn filter_asset_location(_: &MultiAsset, _: &MultiLocation) -> bool {
|
||||
impl ContainsPair<MultiAsset, MultiLocation> for AllAssetLocationsPass {
|
||||
fn contains(_: &MultiAsset, _: &MultiLocation) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,11 +11,13 @@ scale-info = { version = "2.1.2", default-features = false, features = ["derive"
|
||||
serde = { version = "1.0.137", optional = true, features = ["derive"] }
|
||||
log = { version = "0.4.17", default-features = false }
|
||||
|
||||
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true }
|
||||
frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-io = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
|
||||
xcm = { path = "..", default-features = false }
|
||||
xcm-executor = { path = "../xcm-executor", default-features = false }
|
||||
@@ -23,9 +25,8 @@ xcm-executor = { path = "../xcm-executor", default-features = false }
|
||||
[dev-dependencies]
|
||||
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
polkadot-runtime-parachains = { path = "../../runtime/parachains" }
|
||||
sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
xcm-builder = { path = "../xcm-builder" }
|
||||
polkadot-parachain = { path = "../../parachain" }
|
||||
xcm-builder = { path = "../xcm-builder" }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
@@ -35,13 +36,16 @@ std = [
|
||||
"serde",
|
||||
"sp-std/std",
|
||||
"sp-core/std",
|
||||
"sp-io/std",
|
||||
"sp-runtime/std",
|
||||
"frame-benchmarking?/std",
|
||||
"frame-support/std",
|
||||
"frame-system/std",
|
||||
"xcm/std",
|
||||
"xcm-executor/std",
|
||||
]
|
||||
runtime-benchmarks = [
|
||||
"frame-system/runtime-benchmarks"
|
||||
"frame-benchmarking/runtime-benchmarks",
|
||||
"frame-system/runtime-benchmarks",
|
||||
]
|
||||
try-runtime = ["frame-support/try-runtime"]
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
// Copyright 2022 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/>.
|
||||
|
||||
use super::*;
|
||||
use frame_benchmarking::{benchmarks, BenchmarkError, BenchmarkResult};
|
||||
use frame_support::weights::Weight;
|
||||
use frame_system::RawOrigin;
|
||||
use sp_core::{bounded::WeakBoundedVec, ConstU32};
|
||||
use sp_std::prelude::*;
|
||||
use xcm::{latest::prelude::*, v2};
|
||||
|
||||
type RuntimeOrigin<T> = <T as frame_system::Config>::RuntimeOrigin;
|
||||
|
||||
benchmarks! {
|
||||
send {
|
||||
let send_origin = T::SendXcmOrigin::successful_origin();
|
||||
if T::SendXcmOrigin::try_origin(send_origin.clone()).is_err() {
|
||||
return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))
|
||||
}
|
||||
let msg = Xcm(vec![ClearOrigin]);
|
||||
let versioned_dest: VersionedMultiLocation = T::ReachableDest::get().ok_or(
|
||||
BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)),
|
||||
)?
|
||||
.into();
|
||||
let versioned_msg = VersionedXcm::from(msg);
|
||||
}: _<RuntimeOrigin<T>>(send_origin, Box::new(versioned_dest), Box::new(versioned_msg))
|
||||
|
||||
teleport_assets {
|
||||
let asset: MultiAsset = (Here, 10).into();
|
||||
let send_origin = T::ExecuteXcmOrigin::successful_origin();
|
||||
let origin_location = T::ExecuteXcmOrigin::try_origin(send_origin.clone())
|
||||
.map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
|
||||
if !T::XcmTeleportFilter::contains(&(origin_location, vec![asset.clone()])) {
|
||||
return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))
|
||||
}
|
||||
|
||||
let recipient = [0u8; 32];
|
||||
let versioned_dest: VersionedMultiLocation = T::ReachableDest::get().ok_or(
|
||||
BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)),
|
||||
)?
|
||||
.into();
|
||||
let versioned_beneficiary: VersionedMultiLocation =
|
||||
AccountId32 { network: None, id: recipient.into() }.into();
|
||||
let versioned_assets: VersionedMultiAssets = asset.into();
|
||||
}: _<RuntimeOrigin<T>>(send_origin, Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0)
|
||||
|
||||
reserve_transfer_assets {
|
||||
let asset: MultiAsset = (Here, 10).into();
|
||||
let send_origin = T::ExecuteXcmOrigin::successful_origin();
|
||||
let origin_location = T::ExecuteXcmOrigin::try_origin(send_origin.clone())
|
||||
.map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
|
||||
if !T::XcmReserveTransferFilter::contains(&(origin_location, vec![asset.clone()])) {
|
||||
return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))
|
||||
}
|
||||
|
||||
let recipient = [0u8; 32];
|
||||
let versioned_dest: VersionedMultiLocation = T::ReachableDest::get().ok_or(
|
||||
BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)),
|
||||
)?
|
||||
.into();
|
||||
let versioned_beneficiary: VersionedMultiLocation =
|
||||
AccountId32 { network: None, id: recipient.into() }.into();
|
||||
let versioned_assets: VersionedMultiAssets = asset.into();
|
||||
}: _<RuntimeOrigin<T>>(send_origin, Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0)
|
||||
|
||||
execute {
|
||||
let execute_origin = T::ExecuteXcmOrigin::successful_origin();
|
||||
let origin_location = T::ExecuteXcmOrigin::try_origin(execute_origin.clone())
|
||||
.map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
|
||||
let msg = Xcm(vec![ClearOrigin]);
|
||||
if !T::XcmExecuteFilter::contains(&(origin_location, msg.clone())) {
|
||||
return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))
|
||||
}
|
||||
let versioned_msg = VersionedXcm::from(msg);
|
||||
}: _<RuntimeOrigin<T>>(execute_origin, Box::new(versioned_msg), Weight::zero())
|
||||
|
||||
force_xcm_version {
|
||||
let loc = T::ReachableDest::get().ok_or(
|
||||
BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)),
|
||||
)?;
|
||||
let xcm_version = 2;
|
||||
}: _(RawOrigin::Root, Box::new(loc), xcm_version)
|
||||
|
||||
force_default_xcm_version {}: _(RawOrigin::Root, Some(2))
|
||||
|
||||
force_subscribe_version_notify {
|
||||
let versioned_loc: VersionedMultiLocation = T::ReachableDest::get().ok_or(
|
||||
BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)),
|
||||
)?
|
||||
.into();
|
||||
}: _(RawOrigin::Root, Box::new(versioned_loc))
|
||||
|
||||
force_unsubscribe_version_notify {
|
||||
let loc = T::ReachableDest::get().ok_or(
|
||||
BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)),
|
||||
)?;
|
||||
let versioned_loc: VersionedMultiLocation = loc.into();
|
||||
let _ = Pallet::<T>::request_version_notify(loc);
|
||||
}: _(RawOrigin::Root, Box::new(versioned_loc))
|
||||
|
||||
migrate_supported_version {
|
||||
let old_version = XCM_VERSION - 1;
|
||||
let loc = VersionedMultiLocation::from(MultiLocation::from(Parent));
|
||||
SupportedVersion::<T>::insert(old_version, loc, old_version);
|
||||
}: {
|
||||
Pallet::<T>::check_xcm_version_change(VersionMigrationStage::MigrateSupportedVersion, Weight::zero());
|
||||
}
|
||||
|
||||
migrate_version_notifiers {
|
||||
let old_version = XCM_VERSION - 1;
|
||||
let loc = VersionedMultiLocation::from(MultiLocation::from(Parent));
|
||||
VersionNotifiers::<T>::insert(old_version, loc, 0);
|
||||
}: {
|
||||
Pallet::<T>::check_xcm_version_change(VersionMigrationStage::MigrateVersionNotifiers, Weight::zero());
|
||||
}
|
||||
|
||||
already_notified_target {
|
||||
let loc = T::ReachableDest::get().ok_or(
|
||||
BenchmarkError::Override(BenchmarkResult::from_weight(T::DbWeight::get().reads(1))),
|
||||
)?;
|
||||
let loc = VersionedMultiLocation::from(loc);
|
||||
let current_version = T::AdvertisedXcmVersion::get();
|
||||
VersionNotifyTargets::<T>::insert(current_version, loc, (0, Weight::zero(), current_version));
|
||||
}: {
|
||||
Pallet::<T>::check_xcm_version_change(VersionMigrationStage::NotifyCurrentTargets(None), Weight::zero());
|
||||
}
|
||||
|
||||
notify_current_targets {
|
||||
let loc = T::ReachableDest::get().ok_or(
|
||||
BenchmarkError::Override(BenchmarkResult::from_weight(T::DbWeight::get().reads_writes(1, 3))),
|
||||
)?;
|
||||
let loc = VersionedMultiLocation::from(loc);
|
||||
let current_version = T::AdvertisedXcmVersion::get();
|
||||
let old_version = current_version - 1;
|
||||
VersionNotifyTargets::<T>::insert(current_version, loc, (0, Weight::zero(), old_version));
|
||||
}: {
|
||||
Pallet::<T>::check_xcm_version_change(VersionMigrationStage::NotifyCurrentTargets(None), Weight::zero());
|
||||
}
|
||||
|
||||
notify_target_migration_fail {
|
||||
let bad_loc: v2::MultiLocation = v2::Junction::Plurality {
|
||||
id: v2::BodyId::Named(WeakBoundedVec::<u8, ConstU32<32>>::try_from(vec![0; 32])
|
||||
.expect("vec has a length of 32 bits; qed")),
|
||||
part: v2::BodyPart::Voice,
|
||||
}
|
||||
.into();
|
||||
let bad_loc = VersionedMultiLocation::from(bad_loc);
|
||||
let current_version = T::AdvertisedXcmVersion::get();
|
||||
VersionNotifyTargets::<T>::insert(current_version, bad_loc, (0, Weight::zero(), current_version));
|
||||
}: {
|
||||
Pallet::<T>::check_xcm_version_change(VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero());
|
||||
}
|
||||
|
||||
migrate_version_notify_targets {
|
||||
let current_version = T::AdvertisedXcmVersion::get();
|
||||
let old_version = current_version - 1;
|
||||
let loc = VersionedMultiLocation::from(MultiLocation::from(Parent));
|
||||
VersionNotifyTargets::<T>::insert(old_version, loc, (0, Weight::zero(), current_version));
|
||||
}: {
|
||||
Pallet::<T>::check_xcm_version_change(VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero());
|
||||
}
|
||||
|
||||
migrate_and_notify_old_targets {
|
||||
let loc = T::ReachableDest::get().ok_or(
|
||||
BenchmarkError::Override(BenchmarkResult::from_weight(T::DbWeight::get().reads_writes(1, 3))),
|
||||
)?;
|
||||
let loc = VersionedMultiLocation::from(loc);
|
||||
let old_version = T::AdvertisedXcmVersion::get() - 1;
|
||||
VersionNotifyTargets::<T>::insert(old_version, loc, (0, Weight::zero(), old_version));
|
||||
}: {
|
||||
Pallet::<T>::check_xcm_version_change(VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero());
|
||||
}
|
||||
|
||||
impl_benchmark_test_suite!(
|
||||
Pallet,
|
||||
crate::mock::new_test_ext_with_balances(Vec::new()),
|
||||
crate::mock::Test
|
||||
);
|
||||
}
|
||||
+1243
-694
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,63 @@
|
||||
// Copyright 2022 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/>.
|
||||
|
||||
use crate::{Config, Pallet, Store};
|
||||
use frame_support::{
|
||||
pallet_prelude::*,
|
||||
traits::{OnRuntimeUpgrade, StorageVersion},
|
||||
weights::Weight,
|
||||
};
|
||||
|
||||
pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||
|
||||
const DEFAULT_PROOF_SIZE: u64 = 64 * 1024;
|
||||
|
||||
pub mod v1 {
|
||||
use super::*;
|
||||
|
||||
pub struct MigrateToV1<T>(sp_std::marker::PhantomData<T>);
|
||||
impl<T: Config> OnRuntimeUpgrade for MigrateToV1<T> {
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn pre_upgrade() -> Result<sp_std::vec::Vec<u8>, &'static str> {
|
||||
ensure!(StorageVersion::get::<Pallet<T>>() == 0, "must upgrade linearly");
|
||||
|
||||
Ok(sp_std::vec::Vec::new())
|
||||
}
|
||||
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
if StorageVersion::get::<Pallet<T>>() == 0 {
|
||||
let mut weight = T::DbWeight::get().reads(1);
|
||||
|
||||
let translate = |pre: (u64, u64, u32)| -> Option<(u64, Weight, u32)> {
|
||||
weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 1));
|
||||
let translated = (pre.0, Weight::from_parts(pre.1, DEFAULT_PROOF_SIZE), pre.2);
|
||||
log::info!("Migrated VersionNotifyTarget {:?} to {:?}", pre, translated);
|
||||
Some(translated)
|
||||
};
|
||||
|
||||
<Pallet<T> as Store>::VersionNotifyTargets::translate_values(translate);
|
||||
|
||||
log::info!("v1 applied successfully");
|
||||
STORAGE_VERSION.put::<Pallet<T>>();
|
||||
|
||||
weight.saturating_add(T::DbWeight::get().writes(1))
|
||||
} else {
|
||||
log::warn!("skipping v1, should be removed");
|
||||
T::DbWeight::get().reads(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,23 +14,28 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use frame_support::{construct_runtime, parameter_types, traits::Everything};
|
||||
use codec::Encode;
|
||||
use frame_support::{
|
||||
construct_runtime, parameter_types,
|
||||
traits::{Everything, Nothing},
|
||||
weights::Weight,
|
||||
};
|
||||
use polkadot_parachain::primitives::Id as ParaId;
|
||||
use polkadot_runtime_parachains::origin;
|
||||
use sp_core::H256;
|
||||
use sp_runtime::{testing::Header, traits::IdentityLookup, AccountId32};
|
||||
pub use sp_std::{cell::RefCell, fmt::Debug, marker::PhantomData};
|
||||
use xcm::latest::prelude::*;
|
||||
use xcm::prelude::*;
|
||||
use xcm_builder::{
|
||||
AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom,
|
||||
AllowTopLevelPaidExecutionFrom, Case, ChildParachainAsNative, ChildParachainConvertsVia,
|
||||
ChildSystemParachainAsSuperuser, CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfFungible,
|
||||
FixedWeightBounds, IsConcrete, LocationInverter, SignedAccountId32AsNative,
|
||||
SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
|
||||
FixedWeightBounds, IsConcrete, SignedAccountId32AsNative, SignedToAccountId32,
|
||||
SovereignSignedViaLocation, TakeWeightCredit,
|
||||
};
|
||||
use xcm_executor::XcmExecutor;
|
||||
|
||||
use crate as pallet_xcm;
|
||||
use crate::{self as pallet_xcm, TestWeightInfo};
|
||||
|
||||
pub type AccountId = AccountId32;
|
||||
pub type Balance = u128;
|
||||
@@ -74,23 +79,27 @@ pub mod pallet_test_notifier {
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
#[pallet::call_index(0)]
|
||||
#[pallet::weight(1_000_000)]
|
||||
pub fn prepare_new_query(origin: OriginFor<T>) -> DispatchResult {
|
||||
#[pallet::weight(Weight::from_parts(1_000_000, 1_000_000))]
|
||||
pub fn prepare_new_query(origin: OriginFor<T>, querier: MultiLocation) -> DispatchResult {
|
||||
let who = ensure_signed(origin)?;
|
||||
let id = who
|
||||
.using_encoded(|mut d| <[u8; 32]>::decode(&mut d))
|
||||
.map_err(|_| Error::<T>::BadAccountFormat)?;
|
||||
let qid = crate::Pallet::<T>::new_query(
|
||||
Junction::AccountId32 { network: Any, id }.into(),
|
||||
Junction::AccountId32 { network: None, id },
|
||||
100u32.into(),
|
||||
querier,
|
||||
);
|
||||
Self::deposit_event(Event::<T>::QueryPrepared(qid));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pallet::call_index(1)]
|
||||
#[pallet::weight(1_000_000)]
|
||||
pub fn prepare_new_notify_query(origin: OriginFor<T>) -> DispatchResult {
|
||||
#[pallet::weight(Weight::from_parts(1_000_000, 1_000_000))]
|
||||
pub fn prepare_new_notify_query(
|
||||
origin: OriginFor<T>,
|
||||
querier: MultiLocation,
|
||||
) -> DispatchResult {
|
||||
let who = ensure_signed(origin)?;
|
||||
let id = who
|
||||
.using_encoded(|mut d| <[u8; 32]>::decode(&mut d))
|
||||
@@ -98,16 +107,17 @@ pub mod pallet_test_notifier {
|
||||
let call =
|
||||
Call::<T>::notification_received { query_id: 0, response: Default::default() };
|
||||
let qid = crate::Pallet::<T>::new_notify_query(
|
||||
Junction::AccountId32 { network: Any, id }.into(),
|
||||
Junction::AccountId32 { network: None, id },
|
||||
<T as Config>::RuntimeCall::from(call),
|
||||
100u32.into(),
|
||||
querier,
|
||||
);
|
||||
Self::deposit_event(Event::<T>::NotifyQueryPrepared(qid));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pallet::call_index(2)]
|
||||
#[pallet::weight(1_000_000)]
|
||||
#[pallet::weight(Weight::from_parts(1_000_000, 1_000_000))]
|
||||
pub fn notification_received(
|
||||
origin: OriginFor<T>,
|
||||
query_id: QueryId,
|
||||
@@ -150,23 +160,40 @@ pub(crate) fn take_sent_xcm() -> Vec<(MultiLocation, Xcm<()>)> {
|
||||
/// Sender that never returns error, always sends
|
||||
pub struct TestSendXcm;
|
||||
impl SendXcm for TestSendXcm {
|
||||
fn send_xcm(dest: impl Into<MultiLocation>, msg: Xcm<()>) -> SendResult {
|
||||
SENT_XCM.with(|q| q.borrow_mut().push((dest.into(), msg)));
|
||||
Ok(())
|
||||
type Ticket = (MultiLocation, Xcm<()>);
|
||||
fn validate(
|
||||
dest: &mut Option<MultiLocation>,
|
||||
msg: &mut Option<Xcm<()>>,
|
||||
) -> SendResult<(MultiLocation, Xcm<()>)> {
|
||||
let pair = (dest.take().unwrap(), msg.take().unwrap());
|
||||
Ok((pair, MultiAssets::new()))
|
||||
}
|
||||
fn deliver(pair: (MultiLocation, Xcm<()>)) -> Result<XcmHash, SendError> {
|
||||
let hash = fake_message_hash(&pair.1);
|
||||
SENT_XCM.with(|q| q.borrow_mut().push(pair));
|
||||
Ok(hash)
|
||||
}
|
||||
}
|
||||
/// Sender that returns error if `X8` junction and stops routing
|
||||
pub struct TestSendXcmErrX8;
|
||||
impl SendXcm for TestSendXcmErrX8 {
|
||||
fn send_xcm(dest: impl Into<MultiLocation>, msg: Xcm<()>) -> SendResult {
|
||||
let dest = dest.into();
|
||||
type Ticket = (MultiLocation, Xcm<()>);
|
||||
fn validate(
|
||||
dest: &mut Option<MultiLocation>,
|
||||
msg: &mut Option<Xcm<()>>,
|
||||
) -> SendResult<(MultiLocation, Xcm<()>)> {
|
||||
let (dest, msg) = (dest.take().unwrap(), msg.take().unwrap());
|
||||
if dest.len() == 8 {
|
||||
Err(SendError::Transport("Destination location full"))
|
||||
} else {
|
||||
SENT_XCM.with(|q| q.borrow_mut().push((dest, msg)));
|
||||
Ok(())
|
||||
Ok(((dest, msg), MultiAssets::new()))
|
||||
}
|
||||
}
|
||||
fn deliver(pair: (MultiLocation, Xcm<()>)) -> Result<XcmHash, SendError> {
|
||||
let hash = fake_message_hash(&pair.1);
|
||||
SENT_XCM.with(|q| q.borrow_mut().push(pair));
|
||||
Ok(hash)
|
||||
}
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
@@ -219,9 +246,9 @@ impl pallet_balances::Config for Test {
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const RelayLocation: MultiLocation = Here.into();
|
||||
pub const AnyNetwork: NetworkId = NetworkId::Any;
|
||||
pub Ancestry: MultiLocation = Here.into();
|
||||
pub const RelayLocation: MultiLocation = Here.into_location();
|
||||
pub const AnyNetwork: Option<NetworkId> = None;
|
||||
pub UniversalLocation: InteriorMultiLocation = Here;
|
||||
pub UnitWeightCost: u64 = 1_000;
|
||||
}
|
||||
|
||||
@@ -239,10 +266,11 @@ type LocalOriginConverter = (
|
||||
);
|
||||
|
||||
parameter_types! {
|
||||
pub const BaseXcmWeight: u64 = 1_000;
|
||||
pub CurrencyPerSecond: (AssetId, u128) = (Concrete(RelayLocation::get()), 1);
|
||||
pub const BaseXcmWeight: Weight = Weight::from_parts(1_000, 1_000);
|
||||
pub CurrencyPerSecondPerByte: (AssetId, u128, u128) = (Concrete(RelayLocation::get()), 1, 1);
|
||||
pub TrustedAssets: (MultiAssetFilter, MultiLocation) = (All.into(), Here.into());
|
||||
pub const MaxInstructions: u32 = 100;
|
||||
pub const MaxAssetsIntoHolding: u32 = 64;
|
||||
}
|
||||
|
||||
pub type Barrier = (
|
||||
@@ -260,20 +288,34 @@ impl xcm_executor::Config for XcmConfig {
|
||||
type OriginConverter = LocalOriginConverter;
|
||||
type IsReserve = ();
|
||||
type IsTeleporter = Case<TrustedAssets>;
|
||||
type LocationInverter = LocationInverter<Ancestry>;
|
||||
type UniversalLocation = UniversalLocation;
|
||||
type Barrier = Barrier;
|
||||
type Weigher = FixedWeightBounds<BaseXcmWeight, RuntimeCall, MaxInstructions>;
|
||||
type Trader = FixedRateOfFungible<CurrencyPerSecond, ()>;
|
||||
type Trader = FixedRateOfFungible<CurrencyPerSecondPerByte, ()>;
|
||||
type ResponseHandler = XcmPallet;
|
||||
type AssetTrap = XcmPallet;
|
||||
type AssetLocker = ();
|
||||
type AssetExchanger = ();
|
||||
type AssetClaims = XcmPallet;
|
||||
type SubscriptionService = XcmPallet;
|
||||
type PalletInstancesInfo = AllPalletsWithSystem;
|
||||
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
|
||||
type FeeManager = ();
|
||||
type MessageExporter = ();
|
||||
type UniversalAliases = Nothing;
|
||||
type CallDispatcher = RuntimeCall;
|
||||
type SafeCallFilter = Everything;
|
||||
}
|
||||
|
||||
pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, AnyNetwork>;
|
||||
|
||||
parameter_types! {
|
||||
pub static AdvertisedXcmVersion: pallet_xcm::XcmVersion = 2;
|
||||
pub static AdvertisedXcmVersion: pallet_xcm::XcmVersion = 3;
|
||||
}
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
parameter_types! {
|
||||
pub ReachableDest: Option<MultiLocation> = Some(Parachain(1000).into());
|
||||
}
|
||||
|
||||
impl pallet_xcm::Config for Test {
|
||||
@@ -286,11 +328,19 @@ impl pallet_xcm::Config for Test {
|
||||
type XcmTeleportFilter = Everything;
|
||||
type XcmReserveTransferFilter = Everything;
|
||||
type Weigher = FixedWeightBounds<BaseXcmWeight, RuntimeCall, MaxInstructions>;
|
||||
type LocationInverter = LocationInverter<Ancestry>;
|
||||
type UniversalLocation = UniversalLocation;
|
||||
type RuntimeOrigin = RuntimeOrigin;
|
||||
type RuntimeCall = RuntimeCall;
|
||||
const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
|
||||
type AdvertisedXcmVersion = AdvertisedXcmVersion;
|
||||
type TrustedLockers = ();
|
||||
type SovereignAccountOf = AccountId32Aliases<(), AccountId32>;
|
||||
type Currency = Balances;
|
||||
type CurrencyMatcher = IsConcrete<RelayLocation>;
|
||||
type MaxLockers = frame_support::traits::ConstU32<8>;
|
||||
type WeightInfo = TestWeightInfo;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type ReachableDest = ReachableDest;
|
||||
}
|
||||
|
||||
impl origin::Config for Test {}
|
||||
@@ -314,7 +364,10 @@ pub(crate) fn buy_execution<C>(fees: impl Into<MultiAsset>) -> Instruction<C> {
|
||||
BuyExecution { fees: fees.into(), weight_limit: Unlimited }
|
||||
}
|
||||
|
||||
pub(crate) fn buy_limited_execution<C>(fees: impl Into<MultiAsset>, weight: u64) -> Instruction<C> {
|
||||
pub(crate) fn buy_limited_execution<C>(
|
||||
fees: impl Into<MultiAsset>,
|
||||
weight: Weight,
|
||||
) -> Instruction<C> {
|
||||
use xcm::latest::prelude::*;
|
||||
BuyExecution { fees: fees.into(), weight_limit: Limited(weight) }
|
||||
}
|
||||
@@ -338,3 +391,7 @@ pub(crate) fn new_test_ext_with_balances(
|
||||
ext.execute_with(|| System::set_block_number(1));
|
||||
ext
|
||||
}
|
||||
|
||||
pub(crate) fn fake_message_hash<T>(message: &Xcm<T>) -> XcmHash {
|
||||
message.using_encoded(sp_io::hashing::blake2_256)
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,20 +18,13 @@
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
mod v0;
|
||||
mod v1;
|
||||
mod v2;
|
||||
mod v3;
|
||||
mod weight_info;
|
||||
|
||||
#[proc_macro]
|
||||
pub fn impl_conversion_functions_for_multilocation_v0(input: TokenStream) -> TokenStream {
|
||||
v0::multilocation::generate_conversion_functions(input)
|
||||
.unwrap_or_else(syn::Error::into_compile_error)
|
||||
.into()
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn impl_conversion_functions_for_multilocation_v1(input: TokenStream) -> TokenStream {
|
||||
v1::multilocation::generate_conversion_functions(input)
|
||||
pub fn impl_conversion_functions_for_multilocation_v2(input: TokenStream) -> TokenStream {
|
||||
v2::multilocation::generate_conversion_functions(input)
|
||||
.unwrap_or_else(syn::Error::into_compile_error)
|
||||
.into()
|
||||
}
|
||||
@@ -40,3 +33,17 @@ pub fn impl_conversion_functions_for_multilocation_v1(input: TokenStream) -> Tok
|
||||
pub fn derive_xcm_weight_info(item: TokenStream) -> TokenStream {
|
||||
weight_info::derive(item)
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn impl_conversion_functions_for_multilocation_v3(input: TokenStream) -> TokenStream {
|
||||
v3::multilocation::generate_conversion_functions(input)
|
||||
.unwrap_or_else(syn::Error::into_compile_error)
|
||||
.into()
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn impl_conversion_functions_for_junctions_v3(input: TokenStream) -> TokenStream {
|
||||
v3::junctions::generate_conversion_functions(input)
|
||||
.unwrap_or_else(syn::Error::into_compile_error)
|
||||
.into()
|
||||
}
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
// Copyright 2021 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/>.
|
||||
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
|
||||
pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> syn::Result<TokenStream> {
|
||||
if !input.is_empty() {
|
||||
return Err(syn::Error::new(Span::call_site(), "No arguments expected"))
|
||||
}
|
||||
|
||||
let from_tuples = generate_conversion_from_tuples();
|
||||
let from_v1 = generate_conversion_from_v1();
|
||||
|
||||
Ok(quote! {
|
||||
#from_tuples
|
||||
#from_v1
|
||||
})
|
||||
}
|
||||
|
||||
fn generate_conversion_from_tuples() -> TokenStream {
|
||||
let from_tuples = (0..8usize)
|
||||
.map(|num_junctions| {
|
||||
let junctions =
|
||||
(0..=num_junctions).map(|_| format_ident!("Junction")).collect::<Vec<_>>();
|
||||
let idents = (0..=num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
|
||||
let variant = &format_ident!("X{}", num_junctions + 1);
|
||||
let array_size = num_junctions + 1;
|
||||
|
||||
quote! {
|
||||
impl From<( #(#junctions,)* )> for MultiLocation {
|
||||
fn from( ( #(#idents,)* ): ( #(#junctions,)* ) ) -> Self {
|
||||
MultiLocation::#variant( #(#idents),* )
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[Junction; #array_size]> for MultiLocation {
|
||||
fn from(j: [Junction; #array_size]) -> Self {
|
||||
let [#(#idents),*] = j;
|
||||
MultiLocation::#variant( #(#idents),* )
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
|
||||
quote! {
|
||||
impl From<()> for MultiLocation {
|
||||
fn from(_: ()) -> Self {
|
||||
MultiLocation::Null
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Junction> for MultiLocation {
|
||||
fn from(x: Junction) -> Self {
|
||||
MultiLocation::X1(x)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[Junction; 0]> for MultiLocation {
|
||||
fn from(_: [Junction; 0]) -> Self {
|
||||
MultiLocation::Null
|
||||
}
|
||||
}
|
||||
|
||||
#from_tuples
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_conversion_from_v1() -> TokenStream {
|
||||
let match_variants = (0..8u8)
|
||||
.map(|cur_num| {
|
||||
let variant = format_ident!("X{}", cur_num + 1);
|
||||
let idents = (1..=cur_num).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
|
||||
|
||||
quote! {
|
||||
crate::v1::Junctions::#variant( j0 #(, #idents)* ) => res
|
||||
.pushed_with(Junction::from(j0))
|
||||
#( .and_then(|res| res.pushed_with(Junction::from(#idents))) )*
|
||||
.map_err(|_| ()),
|
||||
}
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
|
||||
quote! {
|
||||
impl TryFrom<crate::v1::MultiLocation> for MultiLocation {
|
||||
type Error = ();
|
||||
fn try_from(v1: crate::v1::MultiLocation) -> core::result::Result<Self, ()> {
|
||||
let mut res = MultiLocation::Null;
|
||||
|
||||
for _ in 0..v1.parents {
|
||||
res.push(Junction::Parent)?;
|
||||
}
|
||||
|
||||
match v1.interior {
|
||||
crate::v1::Junctions::Here => Ok(res),
|
||||
#match_variants
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright 2021 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/>.
|
||||
|
||||
pub mod multilocation;
|
||||
@@ -1,206 +0,0 @@
|
||||
// Copyright 2021 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/>.
|
||||
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{Result, Token};
|
||||
|
||||
pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result<TokenStream> {
|
||||
if !input.is_empty() {
|
||||
return Err(syn::Error::new(Span::call_site(), "No arguments expected"))
|
||||
}
|
||||
|
||||
// Support up to 8 Parents in a tuple, assuming that most use cases don't go past 8 parents.
|
||||
let from_tuples = generate_conversion_from_tuples(8);
|
||||
let from_v0 = generate_conversion_from_v0();
|
||||
|
||||
Ok(quote! {
|
||||
#from_tuples
|
||||
#from_v0
|
||||
})
|
||||
}
|
||||
|
||||
fn generate_conversion_from_tuples(max_parents: u8) -> TokenStream {
|
||||
let mut from_tuples = (0..8usize)
|
||||
.map(|num_junctions| {
|
||||
let junctions =
|
||||
(0..=num_junctions).map(|_| format_ident!("Junction")).collect::<Vec<_>>();
|
||||
let idents = (0..=num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
|
||||
let variant = &format_ident!("X{}", num_junctions + 1);
|
||||
let array_size = num_junctions + 1;
|
||||
|
||||
let mut from_tuple = quote! {
|
||||
impl From<( #(#junctions,)* )> for MultiLocation {
|
||||
fn from( ( #(#idents,)* ): ( #(#junctions,)* ) ) -> Self {
|
||||
MultiLocation { parents: 0, interior: Junctions::#variant( #(#idents),* ) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(u8, #(#junctions),*)> for MultiLocation {
|
||||
fn from( ( parents, #(#idents),* ): (u8, #(#junctions),* ) ) -> Self {
|
||||
MultiLocation { parents, interior: Junctions::#variant( #(#idents),* ) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(Ancestor, #(#junctions),*)> for MultiLocation {
|
||||
fn from( ( Ancestor(parents), #(#idents),* ): (Ancestor, #(#junctions),* ) ) -> Self {
|
||||
MultiLocation { parents, interior: Junctions::#variant( #(#idents),* ) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[Junction; #array_size]> for MultiLocation {
|
||||
fn from(j: [Junction; #array_size]) -> Self {
|
||||
let [#(#idents),*] = j;
|
||||
MultiLocation { parents: 0, interior: Junctions::#variant( #(#idents),* ) }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let from_parent_tuples = (1..=max_parents).map(|cur_parents| {
|
||||
let parents = (0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
|
||||
let underscores =
|
||||
(0..cur_parents).map(|_| Token)).collect::<Vec<_>>();
|
||||
|
||||
quote! {
|
||||
impl From<( #(#parents,)* #(#junctions),* )> for MultiLocation {
|
||||
fn from( (#(#underscores,)* #(#idents),*): ( #(#parents,)* #(#junctions),* ) ) -> Self {
|
||||
MultiLocation { parents: #cur_parents, interior: Junctions::#variant( #(#idents),* ) }
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
from_tuple.extend(from_parent_tuples);
|
||||
from_tuple
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
|
||||
let from_parent_junctions_tuples = (1..=max_parents).map(|cur_parents| {
|
||||
let parents = (0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
|
||||
let underscores =
|
||||
(0..cur_parents).map(|_| Token)).collect::<Vec<_>>();
|
||||
|
||||
quote! {
|
||||
impl From<( #(#parents,)* Junctions )> for MultiLocation {
|
||||
fn from( (#(#underscores,)* junctions): ( #(#parents,)* Junctions ) ) -> Self {
|
||||
MultiLocation { parents: #cur_parents, interior: junctions }
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
from_tuples.extend(from_parent_junctions_tuples);
|
||||
|
||||
quote! {
|
||||
impl From<Junctions> for MultiLocation {
|
||||
fn from(junctions: Junctions) -> Self {
|
||||
MultiLocation { parents: 0, interior: junctions }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(u8, Junctions)> for MultiLocation {
|
||||
fn from((parents, interior): (u8, Junctions)) -> Self {
|
||||
MultiLocation { parents, interior }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(Ancestor, Junctions)> for MultiLocation {
|
||||
fn from((Ancestor(parents), interior): (Ancestor, Junctions)) -> Self {
|
||||
MultiLocation { parents, interior }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<()> for MultiLocation {
|
||||
fn from(_: ()) -> Self {
|
||||
MultiLocation { parents: 0, interior: Junctions::Here }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(u8,)> for MultiLocation {
|
||||
fn from((parents,): (u8,)) -> Self {
|
||||
MultiLocation { parents, interior: Junctions::Here }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Junction> for MultiLocation {
|
||||
fn from(x: Junction) -> Self {
|
||||
MultiLocation { parents: 0, interior: Junctions::X1(x) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[Junction; 0]> for MultiLocation {
|
||||
fn from(_: [Junction; 0]) -> Self {
|
||||
MultiLocation { parents: 0, interior: Junctions::Here }
|
||||
}
|
||||
}
|
||||
|
||||
#from_tuples
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_conversion_from_v0() -> TokenStream {
|
||||
let match_variants = (0..8u8)
|
||||
.map(|cur_num| {
|
||||
let num_ancestors = cur_num + 1;
|
||||
let variant = format_ident!("X{}", num_ancestors);
|
||||
let idents = (0..=cur_num).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
|
||||
|
||||
let intermediate_match_arms = (1..num_ancestors)
|
||||
.rev()
|
||||
.map(|parent_count| {
|
||||
let parent_idents =
|
||||
(0..parent_count).map(|j| format_ident!("j{}", j)).collect::<Vec<_>>();
|
||||
let junction_idents = (parent_count..num_ancestors)
|
||||
.map(|j| format_ident!("j{}", j))
|
||||
.collect::<Vec<_>>();
|
||||
let junction_variant = format_ident!("X{}", num_ancestors - parent_count);
|
||||
|
||||
quote! {
|
||||
crate::v0::MultiLocation::#variant( #(#idents),* )
|
||||
if #( #parent_idents.is_parent() )&&* =>
|
||||
Ok(MultiLocation {
|
||||
parents: #parent_count,
|
||||
interior: #junction_variant( #( TryInto::try_into(#junction_idents)? ),* ),
|
||||
}),
|
||||
}
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
|
||||
quote! {
|
||||
crate::v0::MultiLocation::#variant( #(#idents),* )
|
||||
if #( #idents.is_parent() )&&* =>
|
||||
Ok(MultiLocation::ancestor(#num_ancestors)),
|
||||
#intermediate_match_arms
|
||||
crate::v0::MultiLocation::#variant( #(#idents),* ) =>
|
||||
Ok( #variant( #( TryInto::try_into(#idents)? ),* ).into() ),
|
||||
}
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
|
||||
quote! {
|
||||
impl core::convert::TryFrom<crate::v0::MultiLocation> for MultiLocation {
|
||||
type Error = ();
|
||||
fn try_from(mut v0: crate::v0::MultiLocation) -> core::result::Result<Self, ()> {
|
||||
use Junctions::*;
|
||||
|
||||
v0.canonicalize();
|
||||
match v0 {
|
||||
crate::v0::MultiLocation::Null => Ok(Here.into()),
|
||||
#match_variants
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
// Copyright 2021 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/>.
|
||||
|
||||
pub mod multilocation {
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{Result, Token};
|
||||
|
||||
pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result<TokenStream> {
|
||||
if !input.is_empty() {
|
||||
return Err(syn::Error::new(Span::call_site(), "No arguments expected"))
|
||||
}
|
||||
|
||||
// Support up to 8 Parents in a tuple, assuming that most use cases don't go past 8 parents.
|
||||
let from_tuples = generate_conversion_from_tuples(8);
|
||||
let from_v3 = generate_conversion_from_v3();
|
||||
|
||||
Ok(quote! {
|
||||
#from_tuples
|
||||
#from_v3
|
||||
})
|
||||
}
|
||||
|
||||
fn generate_conversion_from_tuples(max_parents: u8) -> TokenStream {
|
||||
let mut from_tuples = (0..8usize)
|
||||
.map(|num_junctions| {
|
||||
let junctions =
|
||||
(0..=num_junctions).map(|_| format_ident!("Junction")).collect::<Vec<_>>();
|
||||
let idents =
|
||||
(0..=num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
|
||||
let variant = &format_ident!("X{}", num_junctions + 1);
|
||||
let array_size = num_junctions + 1;
|
||||
|
||||
let mut from_tuple = quote! {
|
||||
impl From<( #(#junctions,)* )> for MultiLocation {
|
||||
fn from( ( #(#idents,)* ): ( #(#junctions,)* ) ) -> Self {
|
||||
MultiLocation { parents: 0, interior: Junctions::#variant( #(#idents),* ) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(u8, #(#junctions),*)> for MultiLocation {
|
||||
fn from( ( parents, #(#idents),* ): (u8, #(#junctions),* ) ) -> Self {
|
||||
MultiLocation { parents, interior: Junctions::#variant( #(#idents),* ) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(Ancestor, #(#junctions),*)> for MultiLocation {
|
||||
fn from( ( Ancestor(parents), #(#idents),* ): (Ancestor, #(#junctions),* ) ) -> Self {
|
||||
MultiLocation { parents, interior: Junctions::#variant( #(#idents),* ) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[Junction; #array_size]> for MultiLocation {
|
||||
fn from(j: [Junction; #array_size]) -> Self {
|
||||
let [#(#idents),*] = j;
|
||||
MultiLocation { parents: 0, interior: Junctions::#variant( #(#idents),* ) }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let from_parent_tuples = (1..=max_parents).map(|cur_parents| {
|
||||
let parents =
|
||||
(0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
|
||||
let underscores =
|
||||
(0..cur_parents).map(|_| Token)).collect::<Vec<_>>();
|
||||
|
||||
quote! {
|
||||
impl From<( #(#parents,)* #(#junctions),* )> for MultiLocation {
|
||||
fn from( (#(#underscores,)* #(#idents),*): ( #(#parents,)* #(#junctions),* ) ) -> Self {
|
||||
MultiLocation { parents: #cur_parents, interior: Junctions::#variant( #(#idents),* ) }
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
from_tuple.extend(from_parent_tuples);
|
||||
from_tuple
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
|
||||
let from_parent_junctions_tuples = (1..=max_parents).map(|cur_parents| {
|
||||
let parents = (0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
|
||||
let underscores =
|
||||
(0..cur_parents).map(|_| Token)).collect::<Vec<_>>();
|
||||
|
||||
quote! {
|
||||
impl From<( #(#parents,)* Junctions )> for MultiLocation {
|
||||
fn from( (#(#underscores,)* junctions): ( #(#parents,)* Junctions ) ) -> Self {
|
||||
MultiLocation { parents: #cur_parents, interior: junctions }
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
from_tuples.extend(from_parent_junctions_tuples);
|
||||
|
||||
quote! {
|
||||
impl From<Junctions> for MultiLocation {
|
||||
fn from(junctions: Junctions) -> Self {
|
||||
MultiLocation { parents: 0, interior: junctions }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(u8, Junctions)> for MultiLocation {
|
||||
fn from((parents, interior): (u8, Junctions)) -> Self {
|
||||
MultiLocation { parents, interior }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(Ancestor, Junctions)> for MultiLocation {
|
||||
fn from((Ancestor(parents), interior): (Ancestor, Junctions)) -> Self {
|
||||
MultiLocation { parents, interior }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<()> for MultiLocation {
|
||||
fn from(_: ()) -> Self {
|
||||
MultiLocation { parents: 0, interior: Junctions::Here }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(u8,)> for MultiLocation {
|
||||
fn from((parents,): (u8,)) -> Self {
|
||||
MultiLocation { parents, interior: Junctions::Here }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Junction> for MultiLocation {
|
||||
fn from(x: Junction) -> Self {
|
||||
MultiLocation { parents: 0, interior: Junctions::X1(x) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[Junction; 0]> for MultiLocation {
|
||||
fn from(_: [Junction; 0]) -> Self {
|
||||
MultiLocation { parents: 0, interior: Junctions::Here }
|
||||
}
|
||||
}
|
||||
|
||||
#from_tuples
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_conversion_from_v3() -> TokenStream {
|
||||
let match_variants = (0..8u8)
|
||||
.map(|cur_num| {
|
||||
let num_ancestors = cur_num + 1;
|
||||
let variant = format_ident!("X{}", num_ancestors);
|
||||
let idents = (0..=cur_num).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
|
||||
|
||||
quote! {
|
||||
crate::v3::Junctions::#variant( #(#idents),* ) =>
|
||||
#variant( #( core::convert::TryInto::try_into(#idents)? ),* ),
|
||||
}
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
|
||||
quote! {
|
||||
impl core::convert::TryFrom<crate::v3::Junctions> for Junctions {
|
||||
type Error = ();
|
||||
fn try_from(mut new: crate::v3::Junctions) -> core::result::Result<Self, ()> {
|
||||
use Junctions::*;
|
||||
Ok(match new {
|
||||
crate::v3::Junctions::Here => Here,
|
||||
#match_variants
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
// Copyright 2021 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/>.
|
||||
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{Result, Token};
|
||||
|
||||
const MAX_JUNCTIONS: usize = 8;
|
||||
|
||||
pub mod multilocation {
|
||||
use super::*;
|
||||
|
||||
pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result<TokenStream> {
|
||||
if !input.is_empty() {
|
||||
return Err(syn::Error::new(Span::call_site(), "No arguments expected"))
|
||||
}
|
||||
|
||||
let from_tuples = generate_conversion_from_tuples(8, 8);
|
||||
|
||||
Ok(quote! {
|
||||
#from_tuples
|
||||
})
|
||||
}
|
||||
|
||||
fn generate_conversion_from_tuples(max_junctions: usize, max_parents: usize) -> TokenStream {
|
||||
let mut from_tuples = (0..=max_junctions)
|
||||
.map(|num_junctions| {
|
||||
let types = (0..num_junctions).map(|i| format_ident!("J{}", i)).collect::<Vec<_>>();
|
||||
let idents =
|
||||
(0..num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
|
||||
let array_size = num_junctions;
|
||||
let interior = if num_junctions == 0 {
|
||||
quote!(Junctions::Here)
|
||||
} else {
|
||||
let variant = format_ident!("X{}", num_junctions);
|
||||
quote! {
|
||||
Junctions::#variant( #(#idents .into()),* )
|
||||
}
|
||||
};
|
||||
|
||||
let mut from_tuple = quote! {
|
||||
impl< #(#types : Into<Junction>,)* > From<( Ancestor, #( #types ),* )> for MultiLocation {
|
||||
fn from( ( Ancestor(parents), #(#idents),* ): ( Ancestor, #( #types ),* ) ) -> Self {
|
||||
MultiLocation { parents, interior: #interior }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[Junction; #array_size]> for MultiLocation {
|
||||
fn from(j: [Junction; #array_size]) -> Self {
|
||||
let [#(#idents),*] = j;
|
||||
MultiLocation { parents: 0, interior: #interior }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let from_parent_tuples = (0..=max_parents).map(|cur_parents| {
|
||||
let parents =
|
||||
(0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
|
||||
let underscores =
|
||||
(0..cur_parents).map(|_| Token)).collect::<Vec<_>>();
|
||||
|
||||
quote! {
|
||||
impl< #(#types : Into<Junction>,)* > From<( #( #parents , )* #( #types , )* )> for MultiLocation {
|
||||
fn from( ( #(#underscores,)* #(#idents,)* ): ( #(#parents,)* #(#types,)* ) ) -> Self {
|
||||
Self { parents: #cur_parents as u8, interior: #interior }
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
from_tuple.extend(from_parent_tuples);
|
||||
from_tuple
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
|
||||
let from_parent_junctions_tuples = (0..=max_parents).map(|cur_parents| {
|
||||
let parents = (0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
|
||||
let underscores =
|
||||
(0..cur_parents).map(|_| Token)).collect::<Vec<_>>();
|
||||
|
||||
quote! {
|
||||
impl From<( #(#parents,)* Junctions )> for MultiLocation {
|
||||
fn from( (#(#underscores,)* junctions): ( #(#parents,)* Junctions ) ) -> Self {
|
||||
MultiLocation { parents: #cur_parents as u8, interior: junctions }
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
from_tuples.extend(from_parent_junctions_tuples);
|
||||
|
||||
quote! {
|
||||
impl From<(Ancestor, Junctions)> for MultiLocation {
|
||||
fn from((Ancestor(parents), interior): (Ancestor, Junctions)) -> Self {
|
||||
MultiLocation { parents, interior }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Junction> for MultiLocation {
|
||||
fn from(x: Junction) -> Self {
|
||||
MultiLocation { parents: 0, interior: Junctions::X1(x) }
|
||||
}
|
||||
}
|
||||
|
||||
#from_tuples
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod junctions {
|
||||
use super::*;
|
||||
|
||||
pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result<TokenStream> {
|
||||
if !input.is_empty() {
|
||||
return Err(syn::Error::new(Span::call_site(), "No arguments expected"))
|
||||
}
|
||||
|
||||
// Support up to 8 Parents in a tuple, assuming that most use cases don't go past 8 parents.
|
||||
let from_v2 = generate_conversion_from_v2(MAX_JUNCTIONS);
|
||||
let from_tuples = generate_conversion_from_tuples(MAX_JUNCTIONS);
|
||||
|
||||
Ok(quote! {
|
||||
#from_v2
|
||||
#from_tuples
|
||||
})
|
||||
}
|
||||
|
||||
fn generate_conversion_from_tuples(max_junctions: usize) -> TokenStream {
|
||||
(1..=max_junctions)
|
||||
.map(|num_junctions| {
|
||||
let idents =
|
||||
(0..num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
|
||||
let types = (0..num_junctions).map(|i| format_ident!("J{}", i)).collect::<Vec<_>>();
|
||||
let variant = &format_ident!("X{}", num_junctions);
|
||||
|
||||
quote! {
|
||||
impl<#(#types : Into<Junction>,)*> From<( #(#types,)* )> for Junctions {
|
||||
fn from( ( #(#idents,)* ): ( #(#types,)* ) ) -> Self {
|
||||
Self::#variant( #(#idents .into()),* )
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn generate_conversion_from_v2(max_junctions: usize) -> TokenStream {
|
||||
let match_variants = (0..max_junctions)
|
||||
.map(|cur_num| {
|
||||
let num_ancestors = cur_num + 1;
|
||||
let variant = format_ident!("X{}", num_ancestors);
|
||||
let idents = (0..=cur_num).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
|
||||
|
||||
quote! {
|
||||
crate::v2::Junctions::#variant( #(#idents),* ) =>
|
||||
#variant( #( core::convert::TryInto::try_into(#idents)? ),* ),
|
||||
}
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
|
||||
quote! {
|
||||
impl core::convert::TryFrom<crate::v2::Junctions> for Junctions {
|
||||
type Error = ();
|
||||
fn try_from(mut old: crate::v2::Junctions) -> core::result::Result<Self, ()> {
|
||||
use Junctions::*;
|
||||
Ok(match old {
|
||||
crate::v2::Junctions::Here => Here,
|
||||
#match_variants
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+320
-299
@@ -23,17 +23,19 @@
|
||||
#![no_std]
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use derivative::Derivative;
|
||||
use parity_scale_codec::{Decode, Encode, Error as CodecError, Input};
|
||||
use parity_scale_codec::{Decode, Encode, Error as CodecError, Input, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
pub mod v0;
|
||||
pub mod v1;
|
||||
pub mod v2;
|
||||
pub mod v3;
|
||||
|
||||
pub mod lts {
|
||||
pub use super::v3::*;
|
||||
}
|
||||
|
||||
pub mod latest {
|
||||
pub use super::v2::*;
|
||||
pub use super::v3::*;
|
||||
}
|
||||
|
||||
mod double_encoded;
|
||||
@@ -65,241 +67,284 @@ pub trait IntoVersion: Sized {
|
||||
}
|
||||
}
|
||||
|
||||
/// A single `MultiLocation` value, together with its version code.
|
||||
#[derive(Derivative, Encode, Decode, TypeInfo)]
|
||||
#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
|
||||
#[codec(encode_bound())]
|
||||
#[codec(decode_bound())]
|
||||
pub enum VersionedMultiLocation {
|
||||
V0(v0::MultiLocation),
|
||||
V1(v1::MultiLocation),
|
||||
pub trait TryAs<T> {
|
||||
fn try_as(&self) -> Result<&T, ()>;
|
||||
}
|
||||
|
||||
impl IntoVersion for VersionedMultiLocation {
|
||||
fn into_version(self, n: Version) -> Result<Self, ()> {
|
||||
Ok(match n {
|
||||
0 => Self::V0(self.try_into()?),
|
||||
1 | 2 => Self::V1(self.try_into()?),
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
macro_rules! versioned_type {
|
||||
($(#[$attr:meta])* pub enum $n:ident {
|
||||
V3($v3:ty),
|
||||
}) => {
|
||||
#[derive(Derivative, Encode, Decode, TypeInfo)]
|
||||
#[derivative(
|
||||
Clone(bound = ""),
|
||||
Eq(bound = ""),
|
||||
PartialEq(bound = ""),
|
||||
Debug(bound = "")
|
||||
)]
|
||||
#[codec(encode_bound())]
|
||||
#[codec(decode_bound())]
|
||||
$(#[$attr])*
|
||||
pub enum $n {
|
||||
#[codec(index = 0)]
|
||||
V3($v3),
|
||||
}
|
||||
impl $n {
|
||||
pub fn try_as<T>(&self) -> Result<&T, ()> where Self: TryAs<T> {
|
||||
<Self as TryAs<T>>::try_as(&self)
|
||||
}
|
||||
}
|
||||
impl TryAs<$v3> for $n {
|
||||
fn try_as(&self) -> Result<&$v3, ()> {
|
||||
match &self {
|
||||
Self::V3(ref x) => Ok(x),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl IntoVersion for $n {
|
||||
fn into_version(self, n: Version) -> Result<Self, ()> {
|
||||
Ok(match n {
|
||||
3 => Self::V3(self.try_into()?),
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
impl<T: Into<$v3>> From<T> for $n {
|
||||
fn from(x: T) -> Self {
|
||||
$n::V3(x.into())
|
||||
}
|
||||
}
|
||||
impl TryFrom<$n> for $v3 {
|
||||
type Error = ();
|
||||
fn try_from(x: $n) -> Result<Self, ()> {
|
||||
use $n::*;
|
||||
match x {
|
||||
V3(x) => Ok(x),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl MaxEncodedLen for $n {
|
||||
fn max_encoded_len() -> usize {
|
||||
<$v3>::max_encoded_len()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
impl From<v0::MultiLocation> for VersionedMultiLocation {
|
||||
fn from(x: v0::MultiLocation) -> Self {
|
||||
VersionedMultiLocation::V0(x)
|
||||
}
|
||||
}
|
||||
($(#[$attr:meta])* pub enum $n:ident {
|
||||
V2($v2:ty),
|
||||
V3($v3:ty),
|
||||
}) => {
|
||||
#[derive(Derivative, Encode, Decode, TypeInfo)]
|
||||
#[derivative(
|
||||
Clone(bound = ""),
|
||||
Eq(bound = ""),
|
||||
PartialEq(bound = ""),
|
||||
Debug(bound = "")
|
||||
)]
|
||||
#[codec(encode_bound())]
|
||||
#[codec(decode_bound())]
|
||||
$(#[$attr])*
|
||||
pub enum $n {
|
||||
#[codec(index = 0)]
|
||||
V2($v2),
|
||||
#[codec(index = 1)]
|
||||
V3($v3),
|
||||
}
|
||||
impl $n {
|
||||
pub fn try_as<T>(&self) -> Result<&T, ()> where Self: TryAs<T> {
|
||||
<Self as TryAs<T>>::try_as(&self)
|
||||
}
|
||||
}
|
||||
impl TryAs<$v2> for $n {
|
||||
fn try_as(&self) -> Result<&$v2, ()> {
|
||||
match &self {
|
||||
Self::V2(ref x) => Ok(x),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl TryAs<$v3> for $n {
|
||||
fn try_as(&self) -> Result<&$v3, ()> {
|
||||
match &self {
|
||||
Self::V3(ref x) => Ok(x),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl IntoVersion for $n {
|
||||
fn into_version(self, n: Version) -> Result<Self, ()> {
|
||||
Ok(match n {
|
||||
1 | 2 => Self::V2(self.try_into()?),
|
||||
3 => Self::V3(self.try_into()?),
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
impl From<$v2> for $n {
|
||||
fn from(x: $v2) -> Self {
|
||||
$n::V2(x)
|
||||
}
|
||||
}
|
||||
impl<T: Into<$v3>> From<T> for $n {
|
||||
fn from(x: T) -> Self {
|
||||
$n::V3(x.into())
|
||||
}
|
||||
}
|
||||
impl TryFrom<$n> for $v2 {
|
||||
type Error = ();
|
||||
fn try_from(x: $n) -> Result<Self, ()> {
|
||||
use $n::*;
|
||||
match x {
|
||||
V2(x) => Ok(x),
|
||||
V3(x) => x.try_into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl TryFrom<$n> for $v3 {
|
||||
type Error = ();
|
||||
fn try_from(x: $n) -> Result<Self, ()> {
|
||||
use $n::*;
|
||||
match x {
|
||||
V2(x) => x.try_into(),
|
||||
V3(x) => Ok(x),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl MaxEncodedLen for $n {
|
||||
fn max_encoded_len() -> usize {
|
||||
<$v3>::max_encoded_len()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
impl<T: Into<v1::MultiLocation>> From<T> for VersionedMultiLocation {
|
||||
fn from(x: T) -> Self {
|
||||
VersionedMultiLocation::V1(x.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<VersionedMultiLocation> for v0::MultiLocation {
|
||||
type Error = ();
|
||||
fn try_from(x: VersionedMultiLocation) -> Result<Self, ()> {
|
||||
use VersionedMultiLocation::*;
|
||||
match x {
|
||||
V0(x) => Ok(x),
|
||||
V1(x) => x.try_into(),
|
||||
($(#[$attr:meta])* pub enum $n:ident {
|
||||
V2($v2:ty),
|
||||
V3($v3:ty),
|
||||
}) => {
|
||||
#[derive(Derivative, Encode, Decode, TypeInfo)]
|
||||
#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
|
||||
#[codec(encode_bound())]
|
||||
#[codec(decode_bound())]
|
||||
$(#[$attr])*
|
||||
pub enum $n {
|
||||
#[codec(index = 1)]
|
||||
V2($v2),
|
||||
#[codec(index = 2)]
|
||||
V3($v3),
|
||||
}
|
||||
impl $n {
|
||||
pub fn try_as<T>(&self) -> Result<&T, ()> where Self: TryAs<T> {
|
||||
<Self as TryAs<T>>::try_as(&self)
|
||||
}
|
||||
}
|
||||
impl TryAs<$v2> for $n {
|
||||
fn try_as(&self) -> Result<&$v2, ()> {
|
||||
match &self {
|
||||
Self::V2(ref x) => Ok(x),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl TryAs<$v3> for $n {
|
||||
fn try_as(&self) -> Result<&$v3, ()> {
|
||||
match &self {
|
||||
Self::V3(ref x) => Ok(x),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl IntoVersion for $n {
|
||||
fn into_version(self, n: Version) -> Result<Self, ()> {
|
||||
Ok(match n {
|
||||
2 => Self::V2(self.try_into()?),
|
||||
3 => Self::V3(self.try_into()?),
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
impl From<$v2> for $n {
|
||||
fn from(x: $v2) -> Self {
|
||||
$n::V2(x)
|
||||
}
|
||||
}
|
||||
impl<T: Into<$v3>> From<T> for $n {
|
||||
fn from(x: T) -> Self {
|
||||
$n::V3(x.into())
|
||||
}
|
||||
}
|
||||
impl TryFrom<$n> for $v2 {
|
||||
type Error = ();
|
||||
fn try_from(x: $n) -> Result<Self, ()> {
|
||||
use $n::*;
|
||||
match x {
|
||||
V2(x) => Ok(x),
|
||||
V3(x) => x.try_into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl TryFrom<$n> for $v3 {
|
||||
type Error = ();
|
||||
fn try_from(x: $n) -> Result<Self, ()> {
|
||||
use $n::*;
|
||||
match x {
|
||||
V2(x) => x.try_into(),
|
||||
V3(x) => Ok(x),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl MaxEncodedLen for $n {
|
||||
fn max_encoded_len() -> usize {
|
||||
<$v3>::max_encoded_len()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<VersionedMultiLocation> for v1::MultiLocation {
|
||||
type Error = ();
|
||||
fn try_from(x: VersionedMultiLocation) -> Result<Self, ()> {
|
||||
use VersionedMultiLocation::*;
|
||||
match x {
|
||||
V0(x) => x.try_into(),
|
||||
V1(x) => Ok(x),
|
||||
}
|
||||
versioned_type! {
|
||||
/// A single version's `Response` value, together with its version code.
|
||||
pub enum VersionedAssetId {
|
||||
V3(v3::AssetId),
|
||||
}
|
||||
}
|
||||
|
||||
/// A single `Response` value, together with its version code.
|
||||
#[derive(Derivative, Encode, Decode, TypeInfo)]
|
||||
#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
|
||||
#[codec(encode_bound())]
|
||||
#[codec(decode_bound())]
|
||||
pub enum VersionedResponse {
|
||||
V0(v0::Response),
|
||||
V1(v1::Response),
|
||||
V2(v2::Response),
|
||||
}
|
||||
|
||||
impl IntoVersion for VersionedResponse {
|
||||
fn into_version(self, n: Version) -> Result<Self, ()> {
|
||||
Ok(match n {
|
||||
0 => Self::V0(self.try_into()?),
|
||||
1 => Self::V1(self.try_into()?),
|
||||
2 => Self::V2(self.try_into()?),
|
||||
_ => return Err(()),
|
||||
})
|
||||
versioned_type! {
|
||||
/// A single version's `Response` value, together with its version code.
|
||||
pub enum VersionedResponse {
|
||||
V2(v2::Response),
|
||||
V3(v3::Response),
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v0::Response> for VersionedResponse {
|
||||
fn from(x: v0::Response) -> Self {
|
||||
VersionedResponse::V0(x)
|
||||
versioned_type! {
|
||||
/// A single `MultiLocation` value, together with its version code.
|
||||
#[derive(Ord, PartialOrd)]
|
||||
pub enum VersionedMultiLocation {
|
||||
V2(v2::MultiLocation),
|
||||
V3(v3::MultiLocation),
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v1::Response> for VersionedResponse {
|
||||
fn from(x: v1::Response) -> Self {
|
||||
VersionedResponse::V1(x)
|
||||
versioned_type! {
|
||||
/// A single `InteriorMultiLocation` value, together with its version code.
|
||||
pub enum VersionedInteriorMultiLocation {
|
||||
V2(v2::InteriorMultiLocation),
|
||||
V3(v3::InteriorMultiLocation),
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Into<v2::Response>> From<T> for VersionedResponse {
|
||||
fn from(x: T) -> Self {
|
||||
VersionedResponse::V2(x.into())
|
||||
versioned_type! {
|
||||
/// A single `MultiAsset` value, together with its version code.
|
||||
pub enum VersionedMultiAsset {
|
||||
V2(v2::MultiAsset),
|
||||
V3(v3::MultiAsset),
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<VersionedResponse> for v0::Response {
|
||||
type Error = ();
|
||||
fn try_from(x: VersionedResponse) -> Result<Self, ()> {
|
||||
use VersionedResponse::*;
|
||||
match x {
|
||||
V0(x) => Ok(x),
|
||||
V1(x) => x.try_into(),
|
||||
V2(x) => VersionedResponse::V1(x.try_into()?).try_into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<VersionedResponse> for v1::Response {
|
||||
type Error = ();
|
||||
fn try_from(x: VersionedResponse) -> Result<Self, ()> {
|
||||
use VersionedResponse::*;
|
||||
match x {
|
||||
V0(x) => x.try_into(),
|
||||
V1(x) => Ok(x),
|
||||
V2(x) => x.try_into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<VersionedResponse> for v2::Response {
|
||||
type Error = ();
|
||||
fn try_from(x: VersionedResponse) -> Result<Self, ()> {
|
||||
use VersionedResponse::*;
|
||||
match x {
|
||||
V0(x) => VersionedResponse::V1(x.try_into()?).try_into(),
|
||||
V1(x) => x.try_into(),
|
||||
V2(x) => Ok(x),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A single `MultiAsset` value, together with its version code.
|
||||
#[derive(Derivative, Encode, Decode, TypeInfo)]
|
||||
#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
|
||||
#[codec(encode_bound())]
|
||||
#[codec(decode_bound())]
|
||||
pub enum VersionedMultiAsset {
|
||||
V0(v0::MultiAsset),
|
||||
V1(v1::MultiAsset),
|
||||
}
|
||||
|
||||
impl IntoVersion for VersionedMultiAsset {
|
||||
fn into_version(self, n: Version) -> Result<Self, ()> {
|
||||
Ok(match n {
|
||||
0 => Self::V0(self.try_into()?),
|
||||
1 | 2 => Self::V1(self.try_into()?),
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v0::MultiAsset> for VersionedMultiAsset {
|
||||
fn from(x: v0::MultiAsset) -> Self {
|
||||
VersionedMultiAsset::V0(x)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Into<v1::MultiAsset>> From<T> for VersionedMultiAsset {
|
||||
fn from(x: T) -> Self {
|
||||
VersionedMultiAsset::V1(x.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<VersionedMultiAsset> for v0::MultiAsset {
|
||||
type Error = ();
|
||||
fn try_from(x: VersionedMultiAsset) -> Result<Self, ()> {
|
||||
use VersionedMultiAsset::*;
|
||||
match x {
|
||||
V0(x) => Ok(x),
|
||||
V1(x) => x.try_into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<VersionedMultiAsset> for v1::MultiAsset {
|
||||
type Error = ();
|
||||
fn try_from(x: VersionedMultiAsset) -> Result<Self, ()> {
|
||||
use VersionedMultiAsset::*;
|
||||
match x {
|
||||
V0(x) => x.try_into(),
|
||||
V1(x) => Ok(x),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A single `MultiAssets` value, together with its version code.
|
||||
#[derive(Derivative, Encode, Decode, TypeInfo)]
|
||||
#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
|
||||
#[codec(encode_bound())]
|
||||
#[codec(decode_bound())]
|
||||
pub enum VersionedMultiAssets {
|
||||
V0(Vec<v0::MultiAsset>),
|
||||
V1(v1::MultiAssets),
|
||||
}
|
||||
|
||||
impl IntoVersion for VersionedMultiAssets {
|
||||
fn into_version(self, n: Version) -> Result<Self, ()> {
|
||||
Ok(match n {
|
||||
0 => Self::V0(self.try_into()?),
|
||||
1 | 2 => Self::V1(self.try_into()?),
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<v0::MultiAsset>> for VersionedMultiAssets {
|
||||
fn from(x: Vec<v0::MultiAsset>) -> Self {
|
||||
VersionedMultiAssets::V0(x)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Into<v1::MultiAssets>> From<T> for VersionedMultiAssets {
|
||||
fn from(x: T) -> Self {
|
||||
VersionedMultiAssets::V1(x.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<VersionedMultiAssets> for Vec<v0::MultiAsset> {
|
||||
type Error = ();
|
||||
fn try_from(x: VersionedMultiAssets) -> Result<Self, ()> {
|
||||
use VersionedMultiAssets::*;
|
||||
match x {
|
||||
V0(x) => Ok(x),
|
||||
V1(x) => x.try_into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<VersionedMultiAssets> for v1::MultiAssets {
|
||||
type Error = ();
|
||||
fn try_from(x: VersionedMultiAssets) -> Result<Self, ()> {
|
||||
use VersionedMultiAssets::*;
|
||||
match x {
|
||||
V0(x) => x.try_into(),
|
||||
V1(x) => Ok(x),
|
||||
}
|
||||
versioned_type! {
|
||||
/// A single `MultiAssets` value, together with its version code.
|
||||
pub enum VersionedMultiAssets {
|
||||
V2(v2::MultiAssets),
|
||||
V3(v3::MultiAssets),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,61 +355,31 @@ impl TryFrom<VersionedMultiAssets> for v1::MultiAssets {
|
||||
#[codec(decode_bound())]
|
||||
#[scale_info(bounds(), skip_type_params(RuntimeCall))]
|
||||
pub enum VersionedXcm<RuntimeCall> {
|
||||
V0(v0::Xcm<RuntimeCall>),
|
||||
V1(v1::Xcm<RuntimeCall>),
|
||||
#[codec(index = 2)]
|
||||
V2(v2::Xcm<RuntimeCall>),
|
||||
#[codec(index = 3)]
|
||||
V3(v3::Xcm<RuntimeCall>),
|
||||
}
|
||||
|
||||
impl<C> IntoVersion for VersionedXcm<C> {
|
||||
fn into_version(self, n: Version) -> Result<Self, ()> {
|
||||
Ok(match n {
|
||||
0 => Self::V0(self.try_into()?),
|
||||
1 => Self::V1(self.try_into()?),
|
||||
2 => Self::V2(self.try_into()?),
|
||||
3 => Self::V3(self.try_into()?),
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<RuntimeCall> From<v0::Xcm<RuntimeCall>> for VersionedXcm<RuntimeCall> {
|
||||
fn from(x: v0::Xcm<RuntimeCall>) -> Self {
|
||||
VersionedXcm::V0(x)
|
||||
}
|
||||
}
|
||||
|
||||
impl<RuntimeCall> From<v1::Xcm<RuntimeCall>> for VersionedXcm<RuntimeCall> {
|
||||
fn from(x: v1::Xcm<RuntimeCall>) -> Self {
|
||||
VersionedXcm::V1(x)
|
||||
}
|
||||
}
|
||||
|
||||
impl<RuntimeCall> From<v2::Xcm<RuntimeCall>> for VersionedXcm<RuntimeCall> {
|
||||
fn from(x: v2::Xcm<RuntimeCall>) -> Self {
|
||||
VersionedXcm::V2(x)
|
||||
}
|
||||
}
|
||||
|
||||
impl<RuntimeCall> TryFrom<VersionedXcm<RuntimeCall>> for v0::Xcm<RuntimeCall> {
|
||||
type Error = ();
|
||||
fn try_from(x: VersionedXcm<RuntimeCall>) -> Result<Self, ()> {
|
||||
use VersionedXcm::*;
|
||||
match x {
|
||||
V0(x) => Ok(x),
|
||||
V1(x) => x.try_into(),
|
||||
V2(x) => V1(x.try_into()?).try_into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<RuntimeCall> TryFrom<VersionedXcm<RuntimeCall>> for v1::Xcm<RuntimeCall> {
|
||||
type Error = ();
|
||||
fn try_from(x: VersionedXcm<RuntimeCall>) -> Result<Self, ()> {
|
||||
use VersionedXcm::*;
|
||||
match x {
|
||||
V0(x) => x.try_into(),
|
||||
V1(x) => Ok(x),
|
||||
V2(x) => x.try_into(),
|
||||
}
|
||||
impl<RuntimeCall> From<v3::Xcm<RuntimeCall>> for VersionedXcm<RuntimeCall> {
|
||||
fn from(x: v3::Xcm<RuntimeCall>) -> Self {
|
||||
VersionedXcm::V3(x)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,9 +388,19 @@ impl<RuntimeCall> TryFrom<VersionedXcm<RuntimeCall>> for v2::Xcm<RuntimeCall> {
|
||||
fn try_from(x: VersionedXcm<RuntimeCall>) -> Result<Self, ()> {
|
||||
use VersionedXcm::*;
|
||||
match x {
|
||||
V0(x) => V1(x.try_into()?).try_into(),
|
||||
V1(x) => x.try_into(),
|
||||
V2(x) => Ok(x),
|
||||
V3(x) => x.try_into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Call> TryFrom<VersionedXcm<Call>> for v3::Xcm<Call> {
|
||||
type Error = ();
|
||||
fn try_from(x: VersionedXcm<Call>) -> Result<Self, ()> {
|
||||
use VersionedXcm::*;
|
||||
match x {
|
||||
V2(x) => x.try_into(),
|
||||
V3(x) => Ok(x),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -398,28 +423,6 @@ impl WrapVersion for () {
|
||||
}
|
||||
}
|
||||
|
||||
/// `WrapVersion` implementation which attempts to always convert the XCM to version 0 before wrapping it.
|
||||
pub struct AlwaysV0;
|
||||
impl WrapVersion for AlwaysV0 {
|
||||
fn wrap_version<RuntimeCall>(
|
||||
_: &latest::MultiLocation,
|
||||
xcm: impl Into<VersionedXcm<RuntimeCall>>,
|
||||
) -> Result<VersionedXcm<RuntimeCall>, ()> {
|
||||
Ok(VersionedXcm::<RuntimeCall>::V0(xcm.into().try_into()?))
|
||||
}
|
||||
}
|
||||
|
||||
/// `WrapVersion` implementation which attempts to always convert the XCM to version 1 before wrapping it.
|
||||
pub struct AlwaysV1;
|
||||
impl WrapVersion for AlwaysV1 {
|
||||
fn wrap_version<RuntimeCall>(
|
||||
_: &latest::MultiLocation,
|
||||
xcm: impl Into<VersionedXcm<RuntimeCall>>,
|
||||
) -> Result<VersionedXcm<RuntimeCall>, ()> {
|
||||
Ok(VersionedXcm::<RuntimeCall>::V1(xcm.into().try_into()?))
|
||||
}
|
||||
}
|
||||
|
||||
/// `WrapVersion` implementation which attempts to always convert the XCM to version 2 before wrapping it.
|
||||
pub struct AlwaysV2;
|
||||
impl WrapVersion for AlwaysV2 {
|
||||
@@ -431,42 +434,54 @@ impl WrapVersion for AlwaysV2 {
|
||||
}
|
||||
}
|
||||
|
||||
/// `WrapVersion` implementation which attempts to always convert the XCM to the latest version before wrapping it.
|
||||
pub type AlwaysLatest = AlwaysV1;
|
||||
/// `WrapVersion` implementation which attempts to always convert the XCM to version 2 before wrapping it.
|
||||
pub struct AlwaysV3;
|
||||
impl WrapVersion for AlwaysV3 {
|
||||
fn wrap_version<Call>(
|
||||
_: &latest::MultiLocation,
|
||||
xcm: impl Into<VersionedXcm<Call>>,
|
||||
) -> Result<VersionedXcm<Call>, ()> {
|
||||
Ok(VersionedXcm::<Call>::V3(xcm.into().try_into()?))
|
||||
}
|
||||
}
|
||||
|
||||
/// `WrapVersion` implementation which attempts to always convert the XCM to the release version before wrapping it.
|
||||
pub type AlwaysRelease = AlwaysV0;
|
||||
/// `WrapVersion` implementation which attempts to always convert the XCM to the latest version
|
||||
/// before wrapping it.
|
||||
pub type AlwaysLatest = AlwaysV3;
|
||||
|
||||
/// `WrapVersion` implementation which attempts to always convert the XCM to the most recent Long-
|
||||
/// Term-Support version before wrapping it.
|
||||
pub type AlwaysLts = AlwaysV3;
|
||||
|
||||
pub mod prelude {
|
||||
pub use super::{
|
||||
latest::prelude::*, AlwaysLatest, AlwaysRelease, AlwaysV0, AlwaysV1, AlwaysV2, IntoVersion,
|
||||
Unsupported, Version as XcmVersion, VersionedMultiAsset, VersionedMultiAssets,
|
||||
VersionedMultiLocation, VersionedResponse, VersionedXcm, WrapVersion,
|
||||
latest::prelude::*, AlwaysLatest, AlwaysLts, AlwaysV2, AlwaysV3, IntoVersion, Unsupported,
|
||||
Version as XcmVersion, VersionedAssetId, VersionedInteriorMultiLocation,
|
||||
VersionedMultiAsset, VersionedMultiAssets, VersionedMultiLocation, VersionedResponse,
|
||||
VersionedXcm, WrapVersion,
|
||||
};
|
||||
}
|
||||
|
||||
pub mod opaque {
|
||||
pub mod v0 {
|
||||
// Everything from v0
|
||||
pub use crate::v0::*;
|
||||
// Then override with the opaque types in v0
|
||||
pub use crate::v0::opaque::{Order, Xcm};
|
||||
}
|
||||
pub mod v1 {
|
||||
// Everything from v1
|
||||
pub use crate::v1::*;
|
||||
// Then override with the opaque types in v1
|
||||
pub use crate::v1::opaque::{Order, Xcm};
|
||||
}
|
||||
pub mod v2 {
|
||||
// Everything from v1
|
||||
// Everything from v2
|
||||
pub use crate::v2::*;
|
||||
// Then override with the opaque types in v2
|
||||
pub use crate::v2::opaque::{Instruction, Xcm};
|
||||
}
|
||||
pub mod v3 {
|
||||
// Everything from v3
|
||||
pub use crate::v3::*;
|
||||
// Then override with the opaque types in v3
|
||||
pub use crate::v3::opaque::{Instruction, Xcm};
|
||||
}
|
||||
|
||||
pub mod latest {
|
||||
pub use super::v2::*;
|
||||
pub use super::v3::*;
|
||||
}
|
||||
|
||||
pub mod lts {
|
||||
pub use super::v3::*;
|
||||
}
|
||||
|
||||
/// The basic `VersionedXcm` type which just uses the `Vec<u8>` as an encoded call.
|
||||
@@ -477,3 +492,9 @@ pub mod opaque {
|
||||
pub trait GetWeight<W> {
|
||||
fn weight(&self) -> latest::Weight;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn conversion_works() {
|
||||
use latest::prelude::*;
|
||||
let _: VersionedMultiAssets = (Here, 1u128).into();
|
||||
}
|
||||
|
||||
@@ -1,214 +0,0 @@
|
||||
// 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 parity_scale_codec::{Decode, Encode, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
use sp_runtime::{traits::ConstU32, WeakBoundedVec};
|
||||
|
||||
/// A global identifier of an account-bearing consensus system.
|
||||
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
|
||||
pub enum NetworkId {
|
||||
/// Unidentified/any.
|
||||
Any,
|
||||
/// Some named network.
|
||||
Named(WeakBoundedVec<u8, ConstU32<32>>),
|
||||
/// The Polkadot Relay chain
|
||||
Polkadot,
|
||||
/// Kusama.
|
||||
Kusama,
|
||||
}
|
||||
|
||||
/// An identifier of a pluralistic body.
|
||||
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
|
||||
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,
|
||||
}
|
||||
|
||||
/// A part of a pluralistic body.
|
||||
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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)]
|
||||
pub enum Junction {
|
||||
/// The consensus system of which the context is a member and state-wise super-set.
|
||||
///
|
||||
/// NOTE: This item is *not* a sub-consensus item: a consensus system may not identify itself trustlessly as
|
||||
/// a location that includes this junction.
|
||||
Parent,
|
||||
/// 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 From<crate::v1::Junction> for Junction {
|
||||
fn from(v1: crate::v1::Junction) -> Junction {
|
||||
use crate::v1::Junction::*;
|
||||
match v1 {
|
||||
Parachain(id) => Self::Parachain(id),
|
||||
AccountId32 { network, id } => Self::AccountId32 { network, id },
|
||||
AccountIndex64 { network, index } => Self::AccountIndex64 { network, index },
|
||||
AccountKey20 { network, key } => Self::AccountKey20 { network, key },
|
||||
PalletInstance(index) => Self::PalletInstance(index),
|
||||
GeneralIndex(index) => Self::GeneralIndex(index),
|
||||
GeneralKey(key) => Self::GeneralKey(key),
|
||||
OnlyChild => Self::OnlyChild,
|
||||
Plurality { id, part } => Self::Plurality { id, part },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Junction {
|
||||
/// Returns true if this junction is a `Parent` item.
|
||||
pub fn is_parent(&self) -> bool {
|
||||
match self {
|
||||
Junction::Parent => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if this junction can be considered an interior part of its context. This is generally `true`,
|
||||
/// except for the `Parent` item.
|
||||
pub fn is_interior(&self) -> bool {
|
||||
match self {
|
||||
Junction::Parent => false,
|
||||
|
||||
Junction::Parachain(..) |
|
||||
Junction::AccountId32 { .. } |
|
||||
Junction::AccountIndex64 { .. } |
|
||||
Junction::AccountKey20 { .. } |
|
||||
Junction::PalletInstance { .. } |
|
||||
Junction::GeneralIndex { .. } |
|
||||
Junction::GeneralKey(..) |
|
||||
Junction::OnlyChild |
|
||||
Junction::Plurality { .. } => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,389 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! Version 0 of the Cross-Consensus Message format data structures.
|
||||
|
||||
use crate::DoubleEncoded;
|
||||
use alloc::vec::Vec;
|
||||
use core::result;
|
||||
use derivative::Derivative;
|
||||
use parity_scale_codec::{self, Decode, Encode};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
mod junction;
|
||||
mod multi_asset;
|
||||
mod multi_location;
|
||||
mod order;
|
||||
mod traits;
|
||||
use super::v1::{MultiLocation as MultiLocation1, Response as Response1, Xcm as Xcm1};
|
||||
pub use junction::{BodyId, BodyPart, Junction, NetworkId};
|
||||
pub use multi_asset::{AssetInstance, MultiAsset};
|
||||
pub use multi_location::MultiLocation::{self, *};
|
||||
pub use order::Order;
|
||||
pub use traits::{Error, ExecuteXcm, Outcome, Result, SendXcm};
|
||||
|
||||
/// A prelude for importing all types typically used when interacting with XCM messages.
|
||||
pub mod prelude {
|
||||
pub use super::{
|
||||
junction::{BodyId, Junction::*},
|
||||
multi_asset::{
|
||||
AssetInstance::{self, *},
|
||||
MultiAsset::{self, *},
|
||||
},
|
||||
multi_location::MultiLocation::{self, *},
|
||||
order::Order::{self, *},
|
||||
traits::{Error as XcmError, ExecuteXcm, Outcome, Result as XcmResult, SendXcm},
|
||||
Junction::*,
|
||||
OriginKind,
|
||||
Xcm::{self, *},
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: #2841 #XCMENCODE Efficient encodings for MultiAssets, Vec<Order>, using initial byte values 128+ to encode
|
||||
// the number of items in the vector.
|
||||
|
||||
/// 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,
|
||||
}
|
||||
|
||||
/// Response data to a query.
|
||||
#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)]
|
||||
pub enum Response {
|
||||
/// Some assets.
|
||||
Assets(Vec<MultiAsset>),
|
||||
}
|
||||
|
||||
/// Cross-Consensus Message: A message from one consensus system to another.
|
||||
///
|
||||
/// Consensus systems that may send and receive messages include blockchains and smart contracts.
|
||||
///
|
||||
/// All messages are delivered from a known *origin*, expressed as a `MultiLocation`.
|
||||
///
|
||||
/// This is the inner XCM format and is version-sensitive. Messages are typically passed using the outer
|
||||
/// XCM format, known as `VersionedXcm`.
|
||||
#[derive(Derivative, Encode, Decode, TypeInfo)]
|
||||
#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
|
||||
#[codec(encode_bound())]
|
||||
#[codec(decode_bound())]
|
||||
#[scale_info(bounds(), skip_type_params(RuntimeCall))]
|
||||
pub enum Xcm<RuntimeCall> {
|
||||
/// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into `holding`. Execute the
|
||||
/// orders (`effects`).
|
||||
///
|
||||
/// - `assets`: The asset(s) to be withdrawn into holding.
|
||||
/// - `effects`: The order(s) to execute on the holding account.
|
||||
///
|
||||
/// Kind: *Instruction*.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 0)]
|
||||
WithdrawAsset { assets: Vec<MultiAsset>, effects: Vec<Order<RuntimeCall>> },
|
||||
|
||||
/// Asset(s) (`assets`) have been received into the ownership of this system on the `origin` system.
|
||||
///
|
||||
/// Some orders are given (`effects`) which should be executed once the corresponding derivative assets have
|
||||
/// been placed into `holding`.
|
||||
///
|
||||
/// - `assets`: The asset(s) that are minted into holding.
|
||||
/// - `effects`: The order(s) to execute on the holding account.
|
||||
///
|
||||
/// Safety: `origin` must be trusted to have received and be storing `assets` such that they may later be
|
||||
/// withdrawn should this system send a corresponding message.
|
||||
///
|
||||
/// Kind: *Trusted Indication*.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 1)]
|
||||
ReserveAssetDeposit { assets: Vec<MultiAsset>, effects: Vec<Order<RuntimeCall>> },
|
||||
|
||||
/// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets should be
|
||||
/// created on this system.
|
||||
///
|
||||
/// Some orders are given (`effects`) which should be executed once the corresponding derivative assets have
|
||||
/// been placed into `holding`.
|
||||
///
|
||||
/// - `assets`: The asset(s) that are minted into holding.
|
||||
/// - `effects`: The order(s) to execute on the holding account.
|
||||
///
|
||||
/// Safety: `origin` must be trusted to have irrevocably destroyed the `assets` prior as a consequence of
|
||||
/// sending this message.
|
||||
///
|
||||
/// Kind: *Trusted Indication*.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 2)]
|
||||
TeleportAsset { assets: Vec<MultiAsset>, effects: Vec<Order<RuntimeCall>> },
|
||||
|
||||
/// Indication of the contents of the holding account corresponding to the `QueryHolding` order of `query_id`.
|
||||
///
|
||||
/// - `query_id`: The identifier of the query that resulted in this message being sent.
|
||||
/// - `assets`: The message content.
|
||||
///
|
||||
/// Safety: No concerns.
|
||||
///
|
||||
/// Kind: *Information*.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 3)]
|
||||
QueryResponse {
|
||||
#[codec(compact)]
|
||||
query_id: u64,
|
||||
response: Response,
|
||||
},
|
||||
|
||||
/// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets under the
|
||||
/// ownership of `dest` within this consensus system.
|
||||
///
|
||||
/// - `assets`: The asset(s) to be withdrawn.
|
||||
/// - `dest`: The new owner for the assets.
|
||||
///
|
||||
/// Safety: No concerns.
|
||||
///
|
||||
/// Kind: *Instruction*.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 4)]
|
||||
TransferAsset { assets: Vec<MultiAsset>, dest: MultiLocation },
|
||||
|
||||
/// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets under the
|
||||
/// ownership of `dest` within this consensus system.
|
||||
///
|
||||
/// Send an onward XCM message to `dest` of `ReserveAssetDeposit` with the given `effects`.
|
||||
///
|
||||
/// - `assets`: The asset(s) to be withdrawn.
|
||||
/// - `dest`: The new owner for the assets.
|
||||
/// - `effects`: The orders that should be contained in the `ReserveAssetDeposit` which is sent onwards to
|
||||
/// `dest`.
|
||||
///
|
||||
/// Safety: No concerns.
|
||||
///
|
||||
/// Kind: *Instruction*.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 5)]
|
||||
TransferReserveAsset { assets: Vec<MultiAsset>, dest: MultiLocation, effects: Vec<Order<()>> },
|
||||
|
||||
/// Apply the encoded transaction `call`, whose dispatch-origin should be `origin` as expressed by the kind
|
||||
/// of origin `origin_type`.
|
||||
///
|
||||
/// - `origin_type`: The means of expressing the message origin as a dispatch origin.
|
||||
/// - `max_weight`: The weight of `call`; this should be at least the chain's calculated weight and will
|
||||
/// be used in the weight determination arithmetic.
|
||||
/// - `call`: The encoded transaction to be applied.
|
||||
///
|
||||
/// Safety: No concerns.
|
||||
///
|
||||
/// Kind: *Instruction*.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 6)]
|
||||
Transact {
|
||||
origin_type: OriginKind,
|
||||
require_weight_at_most: u64,
|
||||
call: DoubleEncoded<RuntimeCall>,
|
||||
},
|
||||
|
||||
/// A message to notify about a new incoming HRMP channel. This message is meant to be sent by the
|
||||
/// relay-chain to a para.
|
||||
///
|
||||
/// - `sender`: The sender in the to-be opened channel. Also, the initiator of the channel opening.
|
||||
/// - `max_message_size`: The maximum size of a message proposed by the sender.
|
||||
/// - `max_capacity`: The maximum number of messages that can be queued in the channel.
|
||||
///
|
||||
/// Safety: The message should originate directly from the relay-chain.
|
||||
///
|
||||
/// Kind: *System Notification*
|
||||
#[codec(index = 7)]
|
||||
HrmpNewChannelOpenRequest {
|
||||
#[codec(compact)]
|
||||
sender: u32,
|
||||
#[codec(compact)]
|
||||
max_message_size: u32,
|
||||
#[codec(compact)]
|
||||
max_capacity: u32,
|
||||
},
|
||||
|
||||
/// A message to notify about that a previously sent open channel request has been accepted by
|
||||
/// the recipient. That means that the channel will be opened during the next relay-chain session
|
||||
/// change. This message is meant to be sent by the relay-chain to a para.
|
||||
///
|
||||
/// Safety: The message should originate directly from the relay-chain.
|
||||
///
|
||||
/// Kind: *System Notification*
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 8)]
|
||||
HrmpChannelAccepted {
|
||||
#[codec(compact)]
|
||||
recipient: u32,
|
||||
},
|
||||
|
||||
/// A message to notify that the other party in an open channel decided to close it. In particular,
|
||||
/// `initiator` is going to close the channel opened from `sender` to the `recipient`. The close
|
||||
/// will be enacted at the next relay-chain session change. This message is meant to be sent by
|
||||
/// the relay-chain to a para.
|
||||
///
|
||||
/// Safety: The message should originate directly from the relay-chain.
|
||||
///
|
||||
/// Kind: *System Notification*
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 9)]
|
||||
HrmpChannelClosing {
|
||||
#[codec(compact)]
|
||||
initiator: u32,
|
||||
#[codec(compact)]
|
||||
sender: u32,
|
||||
#[codec(compact)]
|
||||
recipient: u32,
|
||||
},
|
||||
|
||||
/// A message to indicate that the embedded XCM is actually arriving on behalf of some consensus
|
||||
/// location within the origin.
|
||||
///
|
||||
/// Safety: `who` must be an interior location of the context. This basically means that no `Parent`
|
||||
/// junctions are allowed in it. This should be verified at the time of XCM execution.
|
||||
///
|
||||
/// Kind: *Instruction*
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 10)]
|
||||
RelayedFrom { who: MultiLocation, message: alloc::boxed::Box<Xcm<RuntimeCall>> },
|
||||
}
|
||||
|
||||
impl<RuntimeCall> Xcm<RuntimeCall> {
|
||||
pub fn into<C>(self) -> Xcm<C> {
|
||||
Xcm::from(self)
|
||||
}
|
||||
pub fn from<C>(xcm: Xcm<C>) -> Self {
|
||||
use Xcm::*;
|
||||
match xcm {
|
||||
WithdrawAsset { assets, effects } =>
|
||||
WithdrawAsset { assets, effects: effects.into_iter().map(Order::into).collect() },
|
||||
ReserveAssetDeposit { assets, effects } => ReserveAssetDeposit {
|
||||
assets,
|
||||
effects: effects.into_iter().map(Order::into).collect(),
|
||||
},
|
||||
TeleportAsset { assets, effects } =>
|
||||
TeleportAsset { assets, effects: effects.into_iter().map(Order::into).collect() },
|
||||
QueryResponse { query_id, response } => QueryResponse { query_id, response },
|
||||
TransferAsset { assets, dest } => TransferAsset { assets, dest },
|
||||
TransferReserveAsset { assets, dest, effects } =>
|
||||
TransferReserveAsset { assets, dest, effects },
|
||||
HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
|
||||
HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
|
||||
HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient },
|
||||
HrmpChannelClosing { initiator, sender, recipient } =>
|
||||
HrmpChannelClosing { initiator, sender, recipient },
|
||||
Transact { origin_type, require_weight_at_most, call } =>
|
||||
Transact { origin_type, require_weight_at_most, call: call.into() },
|
||||
RelayedFrom { who, message } =>
|
||||
RelayedFrom { who, message: alloc::boxed::Box::new((*message).into()) },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod opaque {
|
||||
/// The basic concrete type of `generic::Xcm`, which doesn't make any assumptions about the format of a
|
||||
/// call other than it is pre-encoded.
|
||||
pub type Xcm = super::Xcm<()>;
|
||||
|
||||
pub use super::order::opaque::*;
|
||||
}
|
||||
|
||||
// Convert from a v1 response to a v0 response
|
||||
impl TryFrom<Response1> for Response {
|
||||
type Error = ();
|
||||
fn try_from(new_response: Response1) -> result::Result<Self, ()> {
|
||||
Ok(match new_response {
|
||||
Response1::Assets(assets) => Self::Assets(assets.try_into()?),
|
||||
Response1::Version(..) => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<RuntimeCall> TryFrom<Xcm1<RuntimeCall>> for Xcm<RuntimeCall> {
|
||||
type Error = ();
|
||||
fn try_from(x: Xcm1<RuntimeCall>) -> result::Result<Xcm<RuntimeCall>, ()> {
|
||||
use Xcm::*;
|
||||
Ok(match x {
|
||||
Xcm1::WithdrawAsset { assets, effects } => WithdrawAsset {
|
||||
assets: assets.try_into()?,
|
||||
effects: effects
|
||||
.into_iter()
|
||||
.map(Order::try_from)
|
||||
.collect::<result::Result<_, _>>()?,
|
||||
},
|
||||
Xcm1::ReserveAssetDeposited { assets, effects } => ReserveAssetDeposit {
|
||||
assets: assets.try_into()?,
|
||||
effects: effects
|
||||
.into_iter()
|
||||
.map(Order::try_from)
|
||||
.collect::<result::Result<_, _>>()?,
|
||||
},
|
||||
Xcm1::ReceiveTeleportedAsset { assets, effects } => TeleportAsset {
|
||||
assets: assets.try_into()?,
|
||||
effects: effects
|
||||
.into_iter()
|
||||
.map(Order::try_from)
|
||||
.collect::<result::Result<_, _>>()?,
|
||||
},
|
||||
Xcm1::QueryResponse { query_id, response } =>
|
||||
QueryResponse { query_id, response: response.try_into()? },
|
||||
Xcm1::TransferAsset { assets, beneficiary } =>
|
||||
TransferAsset { assets: assets.try_into()?, dest: beneficiary.try_into()? },
|
||||
Xcm1::TransferReserveAsset { assets, dest, effects } => TransferReserveAsset {
|
||||
assets: assets.try_into()?,
|
||||
dest: dest.try_into()?,
|
||||
effects: effects
|
||||
.into_iter()
|
||||
.map(Order::try_from)
|
||||
.collect::<result::Result<_, _>>()?,
|
||||
},
|
||||
Xcm1::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
|
||||
HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
|
||||
Xcm1::HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient },
|
||||
Xcm1::HrmpChannelClosing { initiator, sender, recipient } =>
|
||||
HrmpChannelClosing { initiator, sender, recipient },
|
||||
Xcm1::Transact { origin_type, require_weight_at_most, call } =>
|
||||
Transact { origin_type, require_weight_at_most, call: call.into() },
|
||||
Xcm1::RelayedFrom { who, message } => RelayedFrom {
|
||||
who: MultiLocation1 { interior: who, parents: 0 }.try_into()?,
|
||||
message: alloc::boxed::Box::new((*message).try_into()?),
|
||||
},
|
||||
Xcm1::SubscribeVersion { .. } | Xcm1::UnsubscribeVersion => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,407 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! Cross-Consensus Message format data structures.
|
||||
|
||||
use super::MultiLocation;
|
||||
use crate::v1::{MultiAssetFilter, MultiAssets, WildMultiAsset};
|
||||
use alloc::{vec, vec::Vec};
|
||||
use core::result;
|
||||
use parity_scale_codec::{self, Decode, Encode};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
pub use crate::v1::AssetInstance;
|
||||
|
||||
/// A single general identifier for an asset.
|
||||
///
|
||||
/// Represents both fungible and non-fungible assets. May only be used to represent a single asset class.
|
||||
///
|
||||
/// Wildcards may or may not be allowed by the interpreting context.
|
||||
///
|
||||
/// Assets classes may be identified in one of two ways: either an abstract identifier or a concrete identifier.
|
||||
/// Implementations may support only one of these. A single asset may be referenced from multiple asset identifiers,
|
||||
/// though will tend to have only a single *preferred* identifier.
|
||||
///
|
||||
/// ### 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.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// 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*.
|
||||
///
|
||||
/// Concrete identifiers are the preferred way of identifying an asset since they are entirely unambiguous.
|
||||
///
|
||||
/// A concrete identifier is represented by a `MultiLocation`. If a system has an unambiguous primary asset (such as
|
||||
/// Bitcoin with BTC or Ethereum with ETH), then it will conventionally be identified as the chain itself. Alternative
|
||||
/// and more specific ways of referring to an asset within a system include:
|
||||
///
|
||||
/// - `<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>/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.
|
||||
///
|
||||
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo)]
|
||||
pub enum MultiAsset {
|
||||
/// No assets. Rarely used.
|
||||
None,
|
||||
|
||||
/// All assets. Typically used for the subset of assets to be used for an `Order`, and in that context means
|
||||
/// "all assets currently in holding".
|
||||
All,
|
||||
|
||||
/// All fungible assets. Typically used for the subset of assets to be used for an `Order`, and in that context
|
||||
/// means "all fungible assets currently in holding".
|
||||
AllFungible,
|
||||
|
||||
/// All non-fungible assets. Typically used for the subset of assets to be used for an `Order`, and in that
|
||||
/// context means "all non-fungible assets currently in holding".
|
||||
AllNonFungible,
|
||||
|
||||
/// All fungible assets of a given abstract asset `id`entifier.
|
||||
AllAbstractFungible { id: Vec<u8> },
|
||||
|
||||
/// All non-fungible assets of a given abstract asset `class`.
|
||||
AllAbstractNonFungible { class: Vec<u8> },
|
||||
|
||||
/// All fungible assets of a given concrete asset `id`entifier.
|
||||
AllConcreteFungible { id: MultiLocation },
|
||||
|
||||
/// All non-fungible assets of a given concrete asset `class`.
|
||||
AllConcreteNonFungible { class: MultiLocation },
|
||||
|
||||
/// Some specific `amount` of the fungible asset identified by an abstract `id`.
|
||||
AbstractFungible {
|
||||
id: Vec<u8>,
|
||||
#[codec(compact)]
|
||||
amount: u128,
|
||||
},
|
||||
|
||||
/// Some specific `instance` of the non-fungible asset whose `class` is identified abstractly.
|
||||
AbstractNonFungible { class: Vec<u8>, instance: AssetInstance },
|
||||
|
||||
/// Some specific `amount` of the fungible asset identified by an concrete `id`.
|
||||
ConcreteFungible {
|
||||
id: MultiLocation,
|
||||
#[codec(compact)]
|
||||
amount: u128,
|
||||
},
|
||||
|
||||
/// Some specific `instance` of the non-fungible asset whose `class` is identified concretely.
|
||||
ConcreteNonFungible { class: MultiLocation, instance: AssetInstance },
|
||||
}
|
||||
|
||||
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 |
|
||||
MultiAsset::AbstractFungible { .. } |
|
||||
MultiAsset::AbstractNonFungible { .. } |
|
||||
MultiAsset::ConcreteFungible { .. } |
|
||||
MultiAsset::ConcreteNonFungible { .. } => false,
|
||||
|
||||
MultiAsset::All |
|
||||
MultiAsset::AllFungible |
|
||||
MultiAsset::AllNonFungible |
|
||||
MultiAsset::AllAbstractFungible { .. } |
|
||||
MultiAsset::AllConcreteFungible { .. } |
|
||||
MultiAsset::AllAbstractNonFungible { .. } |
|
||||
MultiAsset::AllConcreteNonFungible { .. } => true,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_none(&self) -> bool {
|
||||
match self {
|
||||
MultiAsset::None |
|
||||
MultiAsset::AbstractFungible { amount: 0, .. } |
|
||||
MultiAsset::ConcreteFungible { amount: 0, .. } => true,
|
||||
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_fungible(&self) -> bool {
|
||||
match self {
|
||||
MultiAsset::All |
|
||||
MultiAsset::AllFungible |
|
||||
MultiAsset::AllAbstractFungible { .. } |
|
||||
MultiAsset::AllConcreteFungible { .. } |
|
||||
MultiAsset::AbstractFungible { .. } |
|
||||
MultiAsset::ConcreteFungible { .. } => true,
|
||||
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_non_fungible(&self) -> bool {
|
||||
match self {
|
||||
MultiAsset::All |
|
||||
MultiAsset::AllNonFungible |
|
||||
MultiAsset::AllAbstractNonFungible { .. } |
|
||||
MultiAsset::AllConcreteNonFungible { .. } |
|
||||
MultiAsset::AbstractNonFungible { .. } |
|
||||
MultiAsset::ConcreteNonFungible { .. } => true,
|
||||
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_concrete_fungible(&self, id: &MultiLocation) -> bool {
|
||||
match self {
|
||||
MultiAsset::AllFungible => true,
|
||||
MultiAsset::AllConcreteFungible { id: i } |
|
||||
MultiAsset::ConcreteFungible { id: i, .. } => i == id,
|
||||
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_abstract_fungible(&self, id: &[u8]) -> bool {
|
||||
match self {
|
||||
MultiAsset::AllFungible => true,
|
||||
MultiAsset::AllAbstractFungible { id: i } |
|
||||
MultiAsset::AbstractFungible { id: i, .. } => i == id,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_concrete_non_fungible(&self, class: &MultiLocation) -> bool {
|
||||
match self {
|
||||
MultiAsset::AllNonFungible => true,
|
||||
MultiAsset::AllConcreteNonFungible { class: i } |
|
||||
MultiAsset::ConcreteNonFungible { class: i, .. } => i == class,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_abstract_non_fungible(&self, class: &[u8]) -> bool {
|
||||
match self {
|
||||
MultiAsset::AllNonFungible => true,
|
||||
MultiAsset::AllAbstractNonFungible { class: i } |
|
||||
MultiAsset::AbstractNonFungible { class: i, .. } => i == class,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
if inner.is_none() {
|
||||
return true
|
||||
}
|
||||
|
||||
// Everything contains anything.
|
||||
if self.is_all() {
|
||||
return true
|
||||
}
|
||||
// Nothing contains nothing.
|
||||
if self.is_none() {
|
||||
return false
|
||||
}
|
||||
|
||||
match self {
|
||||
// Anything fungible contains "all fungibles"
|
||||
AllFungible => inner.is_fungible(),
|
||||
// Anything non-fungible contains "all non-fungibles"
|
||||
AllNonFungible => inner.is_non_fungible(),
|
||||
|
||||
AllConcreteFungible { id } => inner.is_concrete_fungible(id),
|
||||
AllAbstractFungible { id } => inner.is_abstract_fungible(id),
|
||||
AllConcreteNonFungible { class } => inner.is_concrete_non_fungible(class),
|
||||
AllAbstractNonFungible { class } => inner.is_abstract_non_fungible(class),
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
|
||||
use MultiAsset::*;
|
||||
match self {
|
||||
AllConcreteFungible { ref mut id } |
|
||||
AllConcreteNonFungible { class: ref mut id } |
|
||||
ConcreteFungible { ref mut id, .. } |
|
||||
ConcreteNonFungible { class: ref mut id, .. } =>
|
||||
id.prepend_with(prepend.clone()).map_err(|_| ()),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<crate::v1::MultiAsset> for MultiAsset {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(m: crate::v1::MultiAsset) -> result::Result<MultiAsset, ()> {
|
||||
use crate::v1::{AssetId::*, Fungibility::*};
|
||||
use MultiAsset::*;
|
||||
Ok(match (m.id, m.fun) {
|
||||
(Concrete(id), Fungible(amount)) => ConcreteFungible { id: id.try_into()?, amount },
|
||||
(Concrete(class), NonFungible(instance)) =>
|
||||
ConcreteNonFungible { class: class.try_into()?, instance },
|
||||
(Abstract(id), Fungible(amount)) => AbstractFungible { id, amount },
|
||||
(Abstract(class), NonFungible(instance)) => AbstractNonFungible { class, instance },
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<MultiAssets> for Vec<MultiAsset> {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(m: MultiAssets) -> result::Result<Vec<MultiAsset>, ()> {
|
||||
m.drain().into_iter().map(MultiAsset::try_from).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<WildMultiAsset> for MultiAsset {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(m: WildMultiAsset) -> result::Result<MultiAsset, ()> {
|
||||
use crate::v1::{AssetId::*, WildFungibility::*};
|
||||
use MultiAsset::*;
|
||||
Ok(match m {
|
||||
WildMultiAsset::All => All,
|
||||
WildMultiAsset::AllOf { id, fun } => match (id, fun) {
|
||||
(Concrete(id), Fungible) => AllConcreteFungible { id: id.try_into()? },
|
||||
(Concrete(class), NonFungible) =>
|
||||
AllConcreteNonFungible { class: class.try_into()? },
|
||||
(Abstract(id), Fungible) => AllAbstractFungible { id },
|
||||
(Abstract(class), NonFungible) => AllAbstractNonFungible { class },
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<WildMultiAsset> for Vec<MultiAsset> {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(m: WildMultiAsset) -> result::Result<Vec<MultiAsset>, ()> {
|
||||
Ok(vec![m.try_into()?])
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<MultiAssetFilter> for Vec<MultiAsset> {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(m: MultiAssetFilter) -> result::Result<Vec<MultiAsset>, ()> {
|
||||
match m {
|
||||
MultiAssetFilter::Definite(assets) => assets.try_into(),
|
||||
MultiAssetFilter::Wild(wildcard) => wildcard.try_into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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(9) }
|
||||
.contains(&AbstractNonFungible {
|
||||
class: vec![98u8],
|
||||
instance: AssetInstance::Index(9)
|
||||
}));
|
||||
assert!(!AbstractNonFungible { class: vec![99u8], instance: AssetInstance::Index(8) }
|
||||
.contains(&AbstractNonFungible {
|
||||
class: vec![99u8],
|
||||
instance: AssetInstance::Index(9)
|
||||
}));
|
||||
assert!(AbstractNonFungible { class: vec![99u8], instance: AssetInstance::Index(9) }
|
||||
.contains(&AbstractNonFungible {
|
||||
class: vec![99u8],
|
||||
instance: AssetInstance::Index(9)
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -1,745 +0,0 @@
|
||||
// Copyright 2020-2021 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/>.
|
||||
|
||||
//! Cross-Consensus Message format data structures.
|
||||
|
||||
use super::Junction;
|
||||
use core::{mem, result};
|
||||
use parity_scale_codec::{self, Decode, Encode};
|
||||
|
||||
/// A relative path between state-bearing consensus systems.
|
||||
///
|
||||
/// A location in a consensus system is defined as an *isolatable state machine* held within global consensus. The
|
||||
/// location in question need not have a sophisticated consensus algorithm of its own; a single account within
|
||||
/// Ethereum, for example, could be considered a location.
|
||||
///
|
||||
/// A very-much non-exhaustive list of types of location include:
|
||||
/// - A (normal, layer-1) block chain, e.g. the Bitcoin mainnet or a parachain.
|
||||
/// - A layer-0 super-chain, e.g. the Polkadot Relay chain.
|
||||
/// - A layer-2 smart contract, e.g. an ERC-20 on Ethereum.
|
||||
/// - A logical functional component of a chain, e.g. a single instance of a pallet on a Frame-based Substrate chain.
|
||||
/// - An account.
|
||||
///
|
||||
/// A `MultiLocation` is a *relative identifier*, meaning that it can only be used to define the relative path
|
||||
/// between two locations, and cannot generally be used to refer to a location universally. It is comprised of a
|
||||
/// number of *junctions*, each morphing the previous location, either diving down into one of its internal locations,
|
||||
/// called a *sub-consensus*, or going up into its parent location. Correct `MultiLocation` values must have all
|
||||
/// `Parent` junctions as a prefix to all *sub-consensus* junctions.
|
||||
///
|
||||
/// This specific `MultiLocation` implementation uses a Rust `enum` in order to make pattern matching easier.
|
||||
///
|
||||
/// The `MultiLocation` value of `Null` simply refers to the interpreting consensus system.
|
||||
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, scale_info::TypeInfo)]
|
||||
pub enum MultiLocation {
|
||||
/// The interpreting consensus system.
|
||||
Null,
|
||||
/// A relative path comprising 1 junction.
|
||||
X1(Junction),
|
||||
/// A relative path comprising 2 junctions.
|
||||
X2(Junction, Junction),
|
||||
/// A relative path comprising 3 junctions.
|
||||
X3(Junction, Junction, Junction),
|
||||
/// A relative path comprising 4 junctions.
|
||||
X4(Junction, Junction, Junction, Junction),
|
||||
/// A relative path comprising 5 junctions.
|
||||
X5(Junction, Junction, Junction, Junction, Junction),
|
||||
/// A relative path comprising 6 junctions.
|
||||
X6(Junction, Junction, Junction, Junction, Junction, Junction),
|
||||
/// A relative path comprising 7 junctions.
|
||||
X7(Junction, Junction, Junction, Junction, Junction, Junction, Junction),
|
||||
/// A relative path comprising 8 junctions.
|
||||
X8(Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction),
|
||||
}
|
||||
|
||||
/// Maximum number of junctions a `MultiLocation` can contain.
|
||||
pub const MAX_MULTILOCATION_LENGTH: usize = 8;
|
||||
|
||||
xcm_procedural::impl_conversion_functions_for_multilocation_v0!();
|
||||
|
||||
pub struct MultiLocationIterator(MultiLocation);
|
||||
impl Iterator for MultiLocationIterator {
|
||||
type Item = Junction;
|
||||
fn next(&mut self) -> Option<Junction> {
|
||||
self.0.take_first()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MultiLocationReverseIterator(MultiLocation);
|
||||
impl Iterator for MultiLocationReverseIterator {
|
||||
type Item = Junction;
|
||||
fn next(&mut self) -> Option<Junction> {
|
||||
self.0.take_last()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MultiLocationRefIterator<'a>(&'a MultiLocation, usize);
|
||||
impl<'a> Iterator for MultiLocationRefIterator<'a> {
|
||||
type Item = &'a Junction;
|
||||
fn next(&mut self) -> Option<&'a Junction> {
|
||||
let result = self.0.at(self.1);
|
||||
self.1 += 1;
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MultiLocationReverseRefIterator<'a>(&'a MultiLocation, usize);
|
||||
impl<'a> Iterator for MultiLocationReverseRefIterator<'a> {
|
||||
type Item = &'a Junction;
|
||||
fn next(&mut self) -> Option<&'a Junction> {
|
||||
self.1 += 1;
|
||||
self.0.at(self.0.len().checked_sub(self.1)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl MultiLocation {
|
||||
/// Returns first junction, or `None` if the location is empty.
|
||||
pub fn first(&self) -> Option<&Junction> {
|
||||
match &self {
|
||||
MultiLocation::Null => None,
|
||||
MultiLocation::X1(ref a) => Some(a),
|
||||
MultiLocation::X2(ref a, ..) => Some(a),
|
||||
MultiLocation::X3(ref a, ..) => Some(a),
|
||||
MultiLocation::X4(ref a, ..) => Some(a),
|
||||
MultiLocation::X5(ref a, ..) => Some(a),
|
||||
MultiLocation::X6(ref a, ..) => Some(a),
|
||||
MultiLocation::X7(ref a, ..) => Some(a),
|
||||
MultiLocation::X8(ref a, ..) => Some(a),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns last junction, or `None` if the location is empty.
|
||||
pub fn last(&self) -> Option<&Junction> {
|
||||
match &self {
|
||||
MultiLocation::Null => None,
|
||||
MultiLocation::X1(ref a) => Some(a),
|
||||
MultiLocation::X2(.., ref a) => Some(a),
|
||||
MultiLocation::X3(.., ref a) => Some(a),
|
||||
MultiLocation::X4(.., ref a) => Some(a),
|
||||
MultiLocation::X5(.., ref a) => Some(a),
|
||||
MultiLocation::X6(.., ref a) => Some(a),
|
||||
MultiLocation::X7(.., ref a) => Some(a),
|
||||
MultiLocation::X8(.., ref a) => Some(a),
|
||||
}
|
||||
}
|
||||
|
||||
/// Splits off the first junction, returning the remaining suffix (first item in tuple) and the first element
|
||||
/// (second item in tuple) or `None` if it was empty.
|
||||
pub fn split_first(self) -> (MultiLocation, Option<Junction>) {
|
||||
match self {
|
||||
MultiLocation::Null => (MultiLocation::Null, None),
|
||||
MultiLocation::X1(a) => (MultiLocation::Null, Some(a)),
|
||||
MultiLocation::X2(a, b) => (MultiLocation::X1(b), Some(a)),
|
||||
MultiLocation::X3(a, b, c) => (MultiLocation::X2(b, c), Some(a)),
|
||||
MultiLocation::X4(a, b, c, d) => (MultiLocation::X3(b, c, d), Some(a)),
|
||||
MultiLocation::X5(a, b, c, d, e) => (MultiLocation::X4(b, c, d, e), Some(a)),
|
||||
MultiLocation::X6(a, b, c, d, e, f) => (MultiLocation::X5(b, c, d, e, f), Some(a)),
|
||||
MultiLocation::X7(a, b, c, d, e, f, g) =>
|
||||
(MultiLocation::X6(b, c, d, e, f, g), Some(a)),
|
||||
MultiLocation::X8(a, b, c, d, e, f, g, h) =>
|
||||
(MultiLocation::X7(b, c, d, e, f, g, h), Some(a)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Splits off the last junction, returning the remaining prefix (first item in tuple) and the last element
|
||||
/// (second item in tuple) or `None` if it was empty.
|
||||
pub fn split_last(self) -> (MultiLocation, Option<Junction>) {
|
||||
match self {
|
||||
MultiLocation::Null => (MultiLocation::Null, None),
|
||||
MultiLocation::X1(a) => (MultiLocation::Null, Some(a)),
|
||||
MultiLocation::X2(a, b) => (MultiLocation::X1(a), Some(b)),
|
||||
MultiLocation::X3(a, b, c) => (MultiLocation::X2(a, b), Some(c)),
|
||||
MultiLocation::X4(a, b, c, d) => (MultiLocation::X3(a, b, c), Some(d)),
|
||||
MultiLocation::X5(a, b, c, d, e) => (MultiLocation::X4(a, b, c, d), Some(e)),
|
||||
MultiLocation::X6(a, b, c, d, e, f) => (MultiLocation::X5(a, b, c, d, e), Some(f)),
|
||||
MultiLocation::X7(a, b, c, d, e, f, g) =>
|
||||
(MultiLocation::X6(a, b, c, d, e, f), Some(g)),
|
||||
MultiLocation::X8(a, b, c, d, e, f, g, h) =>
|
||||
(MultiLocation::X7(a, b, c, d, e, f, g), Some(h)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes the first element from `self`, returning it (or `None` if it was empty).
|
||||
pub fn take_first(&mut self) -> Option<Junction> {
|
||||
let mut d = MultiLocation::Null;
|
||||
mem::swap(&mut *self, &mut d);
|
||||
let (tail, head) = d.split_first();
|
||||
*self = tail;
|
||||
head
|
||||
}
|
||||
|
||||
/// Removes the last element from `self`, returning it (or `None` if it was empty).
|
||||
pub fn take_last(&mut self) -> Option<Junction> {
|
||||
let mut d = MultiLocation::Null;
|
||||
mem::swap(&mut *self, &mut d);
|
||||
let (head, tail) = d.split_last();
|
||||
*self = head;
|
||||
tail
|
||||
}
|
||||
|
||||
/// Consumes `self` and returns a `MultiLocation` suffixed with `new`, or an `Err` with the original value of
|
||||
/// `self` in case of overflow.
|
||||
pub fn pushed_with(self, new: Junction) -> result::Result<Self, Self> {
|
||||
Ok(match self {
|
||||
MultiLocation::Null => MultiLocation::X1(new),
|
||||
MultiLocation::X1(a) => MultiLocation::X2(a, new),
|
||||
MultiLocation::X2(a, b) => MultiLocation::X3(a, b, new),
|
||||
MultiLocation::X3(a, b, c) => MultiLocation::X4(a, b, c, new),
|
||||
MultiLocation::X4(a, b, c, d) => MultiLocation::X5(a, b, c, d, new),
|
||||
MultiLocation::X5(a, b, c, d, e) => MultiLocation::X6(a, b, c, d, e, new),
|
||||
MultiLocation::X6(a, b, c, d, e, f) => MultiLocation::X7(a, b, c, d, e, f, new),
|
||||
MultiLocation::X7(a, b, c, d, e, f, g) => MultiLocation::X8(a, b, c, d, e, f, g, new),
|
||||
s => Err(s)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Consumes `self` and returns a `MultiLocation` prefixed with `new`, or an `Err` with the original value of
|
||||
/// `self` in case of overflow.
|
||||
pub fn pushed_front_with(self, new: Junction) -> result::Result<Self, Self> {
|
||||
Ok(match self {
|
||||
MultiLocation::Null => MultiLocation::X1(new),
|
||||
MultiLocation::X1(a) => MultiLocation::X2(new, a),
|
||||
MultiLocation::X2(a, b) => MultiLocation::X3(new, a, b),
|
||||
MultiLocation::X3(a, b, c) => MultiLocation::X4(new, a, b, c),
|
||||
MultiLocation::X4(a, b, c, d) => MultiLocation::X5(new, a, b, c, d),
|
||||
MultiLocation::X5(a, b, c, d, e) => MultiLocation::X6(new, a, b, c, d, e),
|
||||
MultiLocation::X6(a, b, c, d, e, f) => MultiLocation::X7(new, a, b, c, d, e, f),
|
||||
MultiLocation::X7(a, b, c, d, e, f, g) => MultiLocation::X8(new, a, b, c, d, e, f, g),
|
||||
s => Err(s)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the number of junctions in `self`.
|
||||
pub fn len(&self) -> usize {
|
||||
match &self {
|
||||
MultiLocation::Null => 0,
|
||||
MultiLocation::X1(..) => 1,
|
||||
MultiLocation::X2(..) => 2,
|
||||
MultiLocation::X3(..) => 3,
|
||||
MultiLocation::X4(..) => 4,
|
||||
MultiLocation::X5(..) => 5,
|
||||
MultiLocation::X6(..) => 6,
|
||||
MultiLocation::X7(..) => 7,
|
||||
MultiLocation::X8(..) => 8,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the junction at index `i`, or `None` if the location doesn't contain that many elements.
|
||||
pub fn at(&self, i: usize) -> Option<&Junction> {
|
||||
Some(match (i, &self) {
|
||||
(0, MultiLocation::X1(ref a)) => a,
|
||||
(0, MultiLocation::X2(ref a, ..)) => a,
|
||||
(0, MultiLocation::X3(ref a, ..)) => a,
|
||||
(0, MultiLocation::X4(ref a, ..)) => a,
|
||||
(0, MultiLocation::X5(ref a, ..)) => a,
|
||||
(0, MultiLocation::X6(ref a, ..)) => a,
|
||||
(0, MultiLocation::X7(ref a, ..)) => a,
|
||||
(0, MultiLocation::X8(ref a, ..)) => a,
|
||||
(1, MultiLocation::X2(_, ref a)) => a,
|
||||
(1, MultiLocation::X3(_, ref a, ..)) => a,
|
||||
(1, MultiLocation::X4(_, ref a, ..)) => a,
|
||||
(1, MultiLocation::X5(_, ref a, ..)) => a,
|
||||
(1, MultiLocation::X6(_, ref a, ..)) => a,
|
||||
(1, MultiLocation::X7(_, ref a, ..)) => a,
|
||||
(1, MultiLocation::X8(_, ref a, ..)) => a,
|
||||
(2, MultiLocation::X3(_, _, ref a)) => a,
|
||||
(2, MultiLocation::X4(_, _, ref a, ..)) => a,
|
||||
(2, MultiLocation::X5(_, _, ref a, ..)) => a,
|
||||
(2, MultiLocation::X6(_, _, ref a, ..)) => a,
|
||||
(2, MultiLocation::X7(_, _, ref a, ..)) => a,
|
||||
(2, MultiLocation::X8(_, _, ref a, ..)) => a,
|
||||
(3, MultiLocation::X4(_, _, _, ref a)) => a,
|
||||
(3, MultiLocation::X5(_, _, _, ref a, ..)) => a,
|
||||
(3, MultiLocation::X6(_, _, _, ref a, ..)) => a,
|
||||
(3, MultiLocation::X7(_, _, _, ref a, ..)) => a,
|
||||
(3, MultiLocation::X8(_, _, _, ref a, ..)) => a,
|
||||
(4, MultiLocation::X5(_, _, _, _, ref a)) => a,
|
||||
(4, MultiLocation::X6(_, _, _, _, ref a, ..)) => a,
|
||||
(4, MultiLocation::X7(_, _, _, _, ref a, ..)) => a,
|
||||
(4, MultiLocation::X8(_, _, _, _, ref a, ..)) => a,
|
||||
(5, MultiLocation::X6(_, _, _, _, _, ref a)) => a,
|
||||
(5, MultiLocation::X7(_, _, _, _, _, ref a, ..)) => a,
|
||||
(5, MultiLocation::X8(_, _, _, _, _, ref a, ..)) => a,
|
||||
(6, MultiLocation::X7(_, _, _, _, _, _, ref a)) => a,
|
||||
(6, MultiLocation::X8(_, _, _, _, _, _, ref a, ..)) => a,
|
||||
(7, MultiLocation::X8(_, _, _, _, _, _, _, ref a)) => a,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the junction at index `i`, or `None` if the location doesn't contain that many
|
||||
/// elements.
|
||||
pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> {
|
||||
Some(match (i, self) {
|
||||
(0, MultiLocation::X1(ref mut a)) => a,
|
||||
(0, MultiLocation::X2(ref mut a, ..)) => a,
|
||||
(0, MultiLocation::X3(ref mut a, ..)) => a,
|
||||
(0, MultiLocation::X4(ref mut a, ..)) => a,
|
||||
(0, MultiLocation::X5(ref mut a, ..)) => a,
|
||||
(0, MultiLocation::X6(ref mut a, ..)) => a,
|
||||
(0, MultiLocation::X7(ref mut a, ..)) => a,
|
||||
(0, MultiLocation::X8(ref mut a, ..)) => a,
|
||||
(1, MultiLocation::X2(_, ref mut a)) => a,
|
||||
(1, MultiLocation::X3(_, ref mut a, ..)) => a,
|
||||
(1, MultiLocation::X4(_, ref mut a, ..)) => a,
|
||||
(1, MultiLocation::X5(_, ref mut a, ..)) => a,
|
||||
(1, MultiLocation::X6(_, ref mut a, ..)) => a,
|
||||
(1, MultiLocation::X7(_, ref mut a, ..)) => a,
|
||||
(1, MultiLocation::X8(_, ref mut a, ..)) => a,
|
||||
(2, MultiLocation::X3(_, _, ref mut a)) => a,
|
||||
(2, MultiLocation::X4(_, _, ref mut a, ..)) => a,
|
||||
(2, MultiLocation::X5(_, _, ref mut a, ..)) => a,
|
||||
(2, MultiLocation::X6(_, _, ref mut a, ..)) => a,
|
||||
(2, MultiLocation::X7(_, _, ref mut a, ..)) => a,
|
||||
(2, MultiLocation::X8(_, _, ref mut a, ..)) => a,
|
||||
(3, MultiLocation::X4(_, _, _, ref mut a)) => a,
|
||||
(3, MultiLocation::X5(_, _, _, ref mut a, ..)) => a,
|
||||
(3, MultiLocation::X6(_, _, _, ref mut a, ..)) => a,
|
||||
(3, MultiLocation::X7(_, _, _, ref mut a, ..)) => a,
|
||||
(3, MultiLocation::X8(_, _, _, ref mut a, ..)) => a,
|
||||
(4, MultiLocation::X5(_, _, _, _, ref mut a)) => a,
|
||||
(4, MultiLocation::X6(_, _, _, _, ref mut a, ..)) => a,
|
||||
(4, MultiLocation::X7(_, _, _, _, ref mut a, ..)) => a,
|
||||
(4, MultiLocation::X8(_, _, _, _, ref mut a, ..)) => a,
|
||||
(5, MultiLocation::X6(_, _, _, _, _, ref mut a)) => a,
|
||||
(5, MultiLocation::X7(_, _, _, _, _, ref mut a, ..)) => a,
|
||||
(5, MultiLocation::X8(_, _, _, _, _, ref mut a, ..)) => a,
|
||||
(6, MultiLocation::X7(_, _, _, _, _, _, ref mut a)) => a,
|
||||
(6, MultiLocation::X8(_, _, _, _, _, _, ref mut a, ..)) => a,
|
||||
(7, MultiLocation::X8(_, _, _, _, _, _, _, ref mut a)) => a,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns a reference iterator over the junctions.
|
||||
pub fn iter(&self) -> MultiLocationRefIterator {
|
||||
MultiLocationRefIterator(&self, 0)
|
||||
}
|
||||
|
||||
/// Returns a reference iterator over the junctions in reverse.
|
||||
pub fn iter_rev(&self) -> MultiLocationReverseRefIterator {
|
||||
MultiLocationReverseRefIterator(&self, 0)
|
||||
}
|
||||
|
||||
/// Consumes `self` and returns an iterator over the junctions.
|
||||
pub fn into_iter(self) -> MultiLocationIterator {
|
||||
MultiLocationIterator(self)
|
||||
}
|
||||
|
||||
/// Consumes `self` and returns an iterator over the junctions in reverse.
|
||||
pub fn into_iter_rev(self) -> MultiLocationReverseIterator {
|
||||
MultiLocationReverseIterator(self)
|
||||
}
|
||||
|
||||
/// Ensures that self begins with `prefix` and that it has a single `Junction` item following.
|
||||
/// If so, returns a reference to this `Junction` item.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use xcm::v0::{MultiLocation::*, Junction::*};
|
||||
/// # fn main() {
|
||||
/// let mut m = X3(Parent, PalletInstance(3), OnlyChild);
|
||||
/// assert_eq!(m.match_and_split(&X2(Parent, PalletInstance(3))), Some(&OnlyChild));
|
||||
/// assert_eq!(m.match_and_split(&X1(Parent)), None);
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn match_and_split(&self, prefix: &MultiLocation) -> Option<&Junction> {
|
||||
if prefix.len() + 1 != self.len() || !self.starts_with(prefix) {
|
||||
return None
|
||||
}
|
||||
return self.at(prefix.len())
|
||||
}
|
||||
|
||||
/// Returns whether `self` begins with or is equal to `prefix`.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use xcm::v0::{Junction::*, MultiLocation::*};
|
||||
/// let m = X4(Parent, PalletInstance(3), OnlyChild, OnlyChild);
|
||||
/// assert!(m.starts_with(&X2(Parent, PalletInstance(3))));
|
||||
/// assert!(m.starts_with(&m));
|
||||
/// assert!(!m.starts_with(&X2(Parent, GeneralIndex(99))));
|
||||
/// assert!(!m.starts_with(&X1(PalletInstance(3))));
|
||||
/// ```
|
||||
pub fn starts_with(&self, prefix: &MultiLocation) -> bool {
|
||||
if self.len() < prefix.len() {
|
||||
return false
|
||||
}
|
||||
prefix.iter().zip(self.iter()).all(|(l, r)| l == r)
|
||||
}
|
||||
|
||||
/// Mutates `self`, suffixing it with `new`. Returns `Err` in case of overflow.
|
||||
pub fn push(&mut self, new: Junction) -> result::Result<(), ()> {
|
||||
let mut n = MultiLocation::Null;
|
||||
mem::swap(&mut *self, &mut n);
|
||||
match n.pushed_with(new) {
|
||||
Ok(result) => {
|
||||
*self = result;
|
||||
Ok(())
|
||||
},
|
||||
Err(old) => {
|
||||
*self = old;
|
||||
Err(())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Mutates `self`, prefixing it with `new`. Returns `Err` in case of overflow.
|
||||
pub fn push_front(&mut self, new: Junction) -> result::Result<(), ()> {
|
||||
let mut n = MultiLocation::Null;
|
||||
mem::swap(&mut *self, &mut n);
|
||||
match n.pushed_front_with(new) {
|
||||
Ok(result) => {
|
||||
*self = result;
|
||||
Ok(())
|
||||
},
|
||||
Err(old) => {
|
||||
*self = old;
|
||||
Err(())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of `Parent` junctions at the beginning of `self`.
|
||||
pub fn leading_parent_count(&self) -> usize {
|
||||
use Junction::Parent;
|
||||
match self {
|
||||
MultiLocation::X8(Parent, Parent, Parent, Parent, Parent, Parent, Parent, Parent) => 8,
|
||||
|
||||
MultiLocation::X8(Parent, Parent, Parent, Parent, Parent, Parent, Parent, ..) => 7,
|
||||
MultiLocation::X7(Parent, Parent, Parent, Parent, Parent, Parent, Parent) => 7,
|
||||
|
||||
MultiLocation::X8(Parent, Parent, Parent, Parent, Parent, Parent, ..) => 6,
|
||||
MultiLocation::X7(Parent, Parent, Parent, Parent, Parent, Parent, ..) => 6,
|
||||
MultiLocation::X6(Parent, Parent, Parent, Parent, Parent, Parent) => 6,
|
||||
|
||||
MultiLocation::X8(Parent, Parent, Parent, Parent, Parent, ..) => 5,
|
||||
MultiLocation::X7(Parent, Parent, Parent, Parent, Parent, ..) => 5,
|
||||
MultiLocation::X6(Parent, Parent, Parent, Parent, Parent, ..) => 5,
|
||||
MultiLocation::X5(Parent, Parent, Parent, Parent, Parent) => 5,
|
||||
|
||||
MultiLocation::X8(Parent, Parent, Parent, Parent, ..) => 4,
|
||||
MultiLocation::X7(Parent, Parent, Parent, Parent, ..) => 4,
|
||||
MultiLocation::X6(Parent, Parent, Parent, Parent, ..) => 4,
|
||||
MultiLocation::X5(Parent, Parent, Parent, Parent, ..) => 4,
|
||||
MultiLocation::X4(Parent, Parent, Parent, Parent) => 4,
|
||||
|
||||
MultiLocation::X8(Parent, Parent, Parent, ..) => 3,
|
||||
MultiLocation::X7(Parent, Parent, Parent, ..) => 3,
|
||||
MultiLocation::X6(Parent, Parent, Parent, ..) => 3,
|
||||
MultiLocation::X5(Parent, Parent, Parent, ..) => 3,
|
||||
MultiLocation::X4(Parent, Parent, Parent, ..) => 3,
|
||||
MultiLocation::X3(Parent, Parent, Parent) => 3,
|
||||
|
||||
MultiLocation::X8(Parent, Parent, ..) => 2,
|
||||
MultiLocation::X7(Parent, Parent, ..) => 2,
|
||||
MultiLocation::X6(Parent, Parent, ..) => 2,
|
||||
MultiLocation::X5(Parent, Parent, ..) => 2,
|
||||
MultiLocation::X4(Parent, Parent, ..) => 2,
|
||||
MultiLocation::X3(Parent, Parent, ..) => 2,
|
||||
MultiLocation::X2(Parent, Parent) => 2,
|
||||
|
||||
MultiLocation::X8(Parent, ..) => 1,
|
||||
MultiLocation::X7(Parent, ..) => 1,
|
||||
MultiLocation::X6(Parent, ..) => 1,
|
||||
MultiLocation::X5(Parent, ..) => 1,
|
||||
MultiLocation::X4(Parent, ..) => 1,
|
||||
MultiLocation::X3(Parent, ..) => 1,
|
||||
MultiLocation::X2(Parent, ..) => 1,
|
||||
MultiLocation::X1(Parent) => 1,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// This function ensures a multi-junction is in its canonicalized/normalized form, removing
|
||||
/// any internal `[Non-Parent, Parent]` combinations.
|
||||
pub fn canonicalize(&mut self) {
|
||||
let mut normalized = MultiLocation::Null;
|
||||
let mut iter = self.iter();
|
||||
// We build up the the new normalized path by taking items from the original multi-location.
|
||||
// When the next item we would add is `Parent`, we instead remove the last item assuming
|
||||
// it is non-parent.
|
||||
const EXPECT_MESSAGE: &'static str =
|
||||
"`self` is a well formed multi-location with N junctions; \
|
||||
this loop iterates over the junctions of `self`; \
|
||||
the loop can push to the new multi-location at most one time; \
|
||||
thus the size of the new multi-location is at most N junctions; \
|
||||
qed";
|
||||
while let Some(j) = iter.next() {
|
||||
if j == &Junction::Parent {
|
||||
match normalized.last() {
|
||||
None | Some(Junction::Parent) => {},
|
||||
Some(_) => {
|
||||
normalized.take_last();
|
||||
continue
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
normalized.push(j.clone()).expect(EXPECT_MESSAGE);
|
||||
}
|
||||
|
||||
core::mem::swap(self, &mut normalized);
|
||||
}
|
||||
|
||||
/// Mutate `self` so that it is suffixed with `suffix`. The correct normalized form is returned,
|
||||
/// removing any internal `[Non-Parent, Parent]` combinations.
|
||||
///
|
||||
/// In the case of overflow, `self` is unmodified and we return `Err` with `suffix`.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use xcm::v0::{MultiLocation::*, Junction::*};
|
||||
/// # fn main() {
|
||||
/// let mut m = X3(Parent, Parachain(21), OnlyChild);
|
||||
/// assert_eq!(m.append_with(X2(Parent, PalletInstance(3))), Ok(()));
|
||||
/// assert_eq!(m, X3(Parent, Parachain(21), PalletInstance(3)));
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn append_with(&mut self, suffix: MultiLocation) -> Result<(), MultiLocation> {
|
||||
let mut prefix = suffix;
|
||||
core::mem::swap(self, &mut prefix);
|
||||
match self.prepend_with(prefix) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(prefix) => {
|
||||
let mut suffix = prefix;
|
||||
core::mem::swap(self, &mut suffix);
|
||||
Err(suffix)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Mutate `self` so that it is prefixed with `prefix`. The correct normalized form is returned,
|
||||
/// removing any internal [Non-Parent, `Parent`] combinations.
|
||||
///
|
||||
/// In the case of overflow, `self` is unmodified and we return `Err` with `prefix`.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use xcm::v0::{MultiLocation::*, Junction::*, NetworkId::Any};
|
||||
/// # fn main() {
|
||||
/// let mut m = X3(Parent, Parent, PalletInstance(3));
|
||||
/// assert_eq!(m.prepend_with(X3(Parent, Parachain(21), OnlyChild)), Ok(()));
|
||||
/// assert_eq!(m, X2(Parent, PalletInstance(3)));
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn prepend_with(&mut self, prefix: MultiLocation) -> Result<(), MultiLocation> {
|
||||
let mut prefix = prefix;
|
||||
|
||||
// This will guarantee that all `Parent` junctions in the prefix are leading, which is
|
||||
// important for calculating the `skipped` items below.
|
||||
prefix.canonicalize();
|
||||
|
||||
let self_leading_parents = self.leading_parent_count();
|
||||
// These are the number of `non-parent` items in the prefix that we can
|
||||
// potentially remove if the original location leads with parents.
|
||||
let prefix_rest = prefix.len() - prefix.leading_parent_count();
|
||||
// 2 * skipped items will be removed when performing the normalization below.
|
||||
let skipped = self_leading_parents.min(prefix_rest);
|
||||
|
||||
// Pre-pending this prefix would create a multi-location with too many junctions.
|
||||
if self.len() + prefix.len() - 2 * skipped > MAX_MULTILOCATION_LENGTH {
|
||||
return Err(prefix)
|
||||
}
|
||||
|
||||
// Here we cancel out `[Non-Parent, Parent]` items (normalization), where
|
||||
// the non-parent item comes from the end of the prefix, and the parent item
|
||||
// comes from the front of the original location.
|
||||
//
|
||||
// We calculated already how many of these there should be above.
|
||||
for _ in 0..skipped {
|
||||
let _non_parent = prefix.take_last();
|
||||
let _parent = self.take_first();
|
||||
debug_assert!(
|
||||
_non_parent.is_some() && _non_parent != Some(Junction::Parent),
|
||||
"prepend_with should always remove a non-parent from the end of the prefix",
|
||||
);
|
||||
debug_assert!(
|
||||
_parent == Some(Junction::Parent),
|
||||
"prepend_with should always remove a parent from the front of the location",
|
||||
);
|
||||
}
|
||||
|
||||
for j in prefix.into_iter_rev() {
|
||||
self.push_front(j)
|
||||
.expect("len + prefix minus 2*skipped is less than max length; qed");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns true iff `self` is an interior location. For this it may not contain any `Junction`s
|
||||
/// for which `Junction::is_interior` returns `false`. This is generally true, except for the
|
||||
/// `Parent` item.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use xcm::v0::{MultiLocation::*, Junction::*, NetworkId::Any};
|
||||
/// # fn main() {
|
||||
/// let parent = X1(Parent);
|
||||
/// assert_eq!(parent.is_interior(), false);
|
||||
/// let m = X2(PalletInstance(12), AccountIndex64 { network: Any, index: 23 });
|
||||
/// assert_eq!(m.is_interior(), true);
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn is_interior(&self) -> bool {
|
||||
self.iter().all(Junction::is_interior)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::MultiLocation::{self, *};
|
||||
use crate::opaque::v0::{Junction::*, NetworkId::Any};
|
||||
|
||||
#[test]
|
||||
fn match_and_split_works() {
|
||||
let m = X3(Parent, Parachain(42), AccountIndex64 { network: Any, index: 23 });
|
||||
assert_eq!(m.match_and_split(&X1(Parent)), None);
|
||||
assert_eq!(
|
||||
m.match_and_split(&X2(Parent, Parachain(42))),
|
||||
Some(&AccountIndex64 { network: Any, index: 23 })
|
||||
);
|
||||
assert_eq!(m.match_and_split(&m), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn starts_with_works() {
|
||||
let full = X3(Parent, Parachain(1000), AccountIndex64 { network: Any, index: 23 });
|
||||
let identity = full.clone();
|
||||
let prefix = X2(Parent, Parachain(1000));
|
||||
let wrong_parachain = X2(Parent, Parachain(1001));
|
||||
let wrong_account = X3(Parent, Parachain(1000), AccountIndex64 { network: Any, index: 24 });
|
||||
let no_parents = X1(Parachain(1000));
|
||||
let too_many_parents = X3(Parent, Parent, Parachain(1000));
|
||||
|
||||
assert!(full.starts_with(&identity));
|
||||
assert!(full.starts_with(&prefix));
|
||||
assert!(!full.starts_with(&wrong_parachain));
|
||||
assert!(!full.starts_with(&wrong_account));
|
||||
assert!(!full.starts_with(&no_parents));
|
||||
assert!(!full.starts_with(&too_many_parents));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn append_with_works() {
|
||||
let acc = AccountIndex64 { network: Any, index: 23 };
|
||||
let mut m = X2(Parent, Parachain(42));
|
||||
assert_eq!(m.append_with(X2(PalletInstance(3), acc.clone())), Ok(()));
|
||||
assert_eq!(m, X4(Parent, Parachain(42), PalletInstance(3), acc.clone()));
|
||||
|
||||
// cannot append to create overly long multilocation
|
||||
let acc = AccountIndex64 { network: Any, index: 23 };
|
||||
let mut m = X7(Parent, Parent, Parent, Parent, Parent, Parent, Parachain(42));
|
||||
let suffix = X2(PalletInstance(3), acc.clone());
|
||||
assert_eq!(m.append_with(suffix.clone()), Err(suffix));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn prepend_with_works() {
|
||||
let mut m = X3(Parent, Parachain(42), AccountIndex64 { network: Any, index: 23 });
|
||||
assert_eq!(m.prepend_with(X2(Parent, OnlyChild)), Ok(()));
|
||||
assert_eq!(m, X3(Parent, Parachain(42), AccountIndex64 { network: Any, index: 23 }));
|
||||
|
||||
// cannot prepend to create overly long multilocation
|
||||
let mut m = X7(Parent, Parent, Parent, Parent, Parent, Parent, Parachain(42));
|
||||
let prefix = X2(Parent, Parent);
|
||||
assert_eq!(m.prepend_with(prefix.clone()), Err(prefix));
|
||||
|
||||
// Can handle shared prefix and resizing correctly.
|
||||
let mut m = X1(Parent);
|
||||
let prefix = X8(
|
||||
Parachain(100),
|
||||
OnlyChild,
|
||||
OnlyChild,
|
||||
OnlyChild,
|
||||
OnlyChild,
|
||||
OnlyChild,
|
||||
OnlyChild,
|
||||
Parent,
|
||||
);
|
||||
assert_eq!(m.prepend_with(prefix.clone()), Ok(()));
|
||||
assert_eq!(m, X5(Parachain(100), OnlyChild, OnlyChild, OnlyChild, OnlyChild));
|
||||
|
||||
let mut m = X1(Parent);
|
||||
let prefix = X8(Parent, Parent, Parent, Parent, Parent, Parent, Parent, Parent);
|
||||
assert_eq!(m.prepend_with(prefix.clone()), Err(prefix));
|
||||
|
||||
let mut m = X1(Parent);
|
||||
let prefix = X7(Parent, Parent, Parent, Parent, Parent, Parent, Parent);
|
||||
assert_eq!(m.prepend_with(prefix.clone()), Ok(()));
|
||||
assert_eq!(m, X8(Parent, Parent, Parent, Parent, Parent, Parent, Parent, Parent));
|
||||
|
||||
let mut m = X1(Parent);
|
||||
let prefix = X8(Parent, Parent, Parent, Parent, OnlyChild, Parent, Parent, Parent);
|
||||
assert_eq!(m.prepend_with(prefix.clone()), Ok(()));
|
||||
assert_eq!(m, X7(Parent, Parent, Parent, Parent, Parent, Parent, Parent));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn canonicalize_works() {
|
||||
let mut m = X1(Parent);
|
||||
m.canonicalize();
|
||||
assert_eq!(m, X1(Parent));
|
||||
|
||||
let mut m = X1(Parachain(1));
|
||||
m.canonicalize();
|
||||
assert_eq!(m, X1(Parachain(1)));
|
||||
|
||||
let mut m = X6(Parent, Parachain(1), Parent, Parachain(2), Parent, Parachain(3));
|
||||
m.canonicalize();
|
||||
assert_eq!(m, X2(Parent, Parachain(3)));
|
||||
|
||||
let mut m = X5(Parachain(1), Parent, Parachain(2), Parent, Parachain(3));
|
||||
m.canonicalize();
|
||||
assert_eq!(m, X1(Parachain(3)));
|
||||
|
||||
let mut m = X6(Parachain(1), Parent, Parachain(2), Parent, Parachain(3), Parent);
|
||||
m.canonicalize();
|
||||
assert_eq!(m, Null);
|
||||
|
||||
let mut m = X5(Parachain(1), Parent, Parent, Parent, Parachain(3));
|
||||
m.canonicalize();
|
||||
assert_eq!(m, X3(Parent, Parent, Parachain(3)));
|
||||
|
||||
let mut m = X4(Parachain(1), Parachain(2), Parent, Parent);
|
||||
m.canonicalize();
|
||||
assert_eq!(m, Null);
|
||||
|
||||
let mut m = X4(Parent, Parent, Parachain(1), Parachain(2));
|
||||
m.canonicalize();
|
||||
assert_eq!(m, X4(Parent, Parent, Parachain(1), Parachain(2)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn conversion_from_other_types_works() {
|
||||
use crate::v1::{self, Junction, Junctions};
|
||||
|
||||
fn takes_multilocation<Arg: Into<MultiLocation>>(_arg: Arg) {}
|
||||
|
||||
takes_multilocation(Null);
|
||||
takes_multilocation(Parent);
|
||||
takes_multilocation([Parent, Parachain(4)]);
|
||||
|
||||
assert_eq!(v1::MultiLocation::here().try_into(), Ok(MultiLocation::Null));
|
||||
assert_eq!(
|
||||
v1::MultiLocation::new(1, Junctions::X1(Junction::Parachain(8))).try_into(),
|
||||
Ok(X2(Parent, Parachain(8))),
|
||||
);
|
||||
assert_eq!(
|
||||
v1::MultiLocation::new(24, Junctions::Here).try_into(),
|
||||
Err::<MultiLocation, ()>(()),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! Version 0 of the Cross-Consensus Message format data structures.
|
||||
|
||||
use super::{super::v1::Order as Order1, MultiAsset, MultiLocation, Xcm};
|
||||
use alloc::vec::Vec;
|
||||
use core::result;
|
||||
use derivative::Derivative;
|
||||
use parity_scale_codec::{self, Decode, Encode};
|
||||
|
||||
/// An instruction to be executed on some or all of the assets in holding, used by asset-related XCM messages.
|
||||
#[derive(Derivative, Encode, Decode, scale_info::TypeInfo)]
|
||||
#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
|
||||
#[codec(encode_bound())]
|
||||
#[codec(decode_bound())]
|
||||
#[scale_info(bounds(), skip_type_params(RuntimeCall))]
|
||||
pub enum Order<RuntimeCall> {
|
||||
/// Do nothing. Not generally used.
|
||||
#[codec(index = 0)]
|
||||
Null,
|
||||
|
||||
/// Remove the asset(s) (`assets`) from holding and place equivalent assets under the ownership of `dest` within
|
||||
/// this consensus system.
|
||||
///
|
||||
/// - `assets`: The asset(s) to remove from holding.
|
||||
/// - `dest`: The new owner for the assets.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 1)]
|
||||
DepositAsset { assets: Vec<MultiAsset>, dest: MultiLocation },
|
||||
|
||||
/// Remove the asset(s) (`assets`) from holding and place equivalent assets under the ownership of `dest` within
|
||||
/// this consensus system.
|
||||
///
|
||||
/// Send an onward XCM message to `dest` of `ReserveAssetDeposit` with the given `effects`.
|
||||
///
|
||||
/// - `assets`: The asset(s) to remove from holding.
|
||||
/// - `dest`: The new owner for the assets.
|
||||
/// - `effects`: The orders that should be contained in the `ReserveAssetDeposit` which is sent onwards to
|
||||
/// `dest`.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 2)]
|
||||
DepositReserveAsset { assets: Vec<MultiAsset>, dest: MultiLocation, effects: Vec<Order<()>> },
|
||||
|
||||
/// Remove the asset(s) (`give`) from holding and replace them with alternative assets.
|
||||
///
|
||||
/// The minimum amount of assets to be received into holding for the order not to fail may be stated.
|
||||
///
|
||||
/// - `give`: The asset(s) to remove from holding.
|
||||
/// - `receive`: The minimum amount of assets(s) which `give` should be exchanged for. The meaning of wildcards
|
||||
/// is undefined and they should be not be used.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 3)]
|
||||
ExchangeAsset { give: Vec<MultiAsset>, receive: Vec<MultiAsset> },
|
||||
|
||||
/// Remove the asset(s) (`assets`) from holding and send a `WithdrawAsset` XCM message to a reserve location.
|
||||
///
|
||||
/// - `assets`: The asset(s) to remove from holding.
|
||||
/// - `reserve`: A valid location that acts as a reserve for all asset(s) in `assets`. The sovereign account
|
||||
/// of this consensus system *on the reserve location* will have appropriate assets withdrawn and `effects` will
|
||||
/// be executed on them. There will typically be only one valid location on any given asset/chain combination.
|
||||
/// - `effects`: The orders to execute on the assets once withdrawn *on the reserve location*.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 4)]
|
||||
InitiateReserveWithdraw {
|
||||
assets: Vec<MultiAsset>,
|
||||
reserve: MultiLocation,
|
||||
effects: Vec<Order<()>>,
|
||||
},
|
||||
|
||||
/// Remove the asset(s) (`assets`) from holding and send a `TeleportAsset` XCM message to a destination location.
|
||||
///
|
||||
/// - `assets`: The asset(s) to remove from holding.
|
||||
/// - `destination`: A valid location that has a bi-lateral teleportation arrangement.
|
||||
/// - `effects`: The orders to execute on the assets once arrived *on the destination location*.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 5)]
|
||||
InitiateTeleport { assets: Vec<MultiAsset>, dest: MultiLocation, effects: Vec<Order<()>> },
|
||||
|
||||
/// Send a `Balances` XCM message with the `assets` value equal to the holding contents, or a portion thereof.
|
||||
///
|
||||
/// - `query_id`: An identifier that will be replicated into the returned XCM message.
|
||||
/// - `dest`: A valid destination for the returned XCM message. This may be limited to the current origin.
|
||||
/// - `assets`: A filter for the assets that should be reported back. The assets reported back will be, asset-
|
||||
/// wise, *the lesser of this value and the holding account*. No wildcards will be used when reporting assets
|
||||
/// back.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 6)]
|
||||
QueryHolding {
|
||||
#[codec(compact)]
|
||||
query_id: u64,
|
||||
dest: MultiLocation,
|
||||
assets: Vec<MultiAsset>,
|
||||
},
|
||||
|
||||
/// Pay for the execution of some XCM with up to `weight` picoseconds of execution time, paying for this with
|
||||
/// up to `fees` from the holding account.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 7)]
|
||||
BuyExecution {
|
||||
fees: MultiAsset,
|
||||
weight: u64,
|
||||
debt: u64,
|
||||
halt_on_error: bool,
|
||||
xcm: Vec<Xcm<RuntimeCall>>,
|
||||
},
|
||||
}
|
||||
|
||||
pub mod opaque {
|
||||
pub type Order = super::Order<()>;
|
||||
}
|
||||
|
||||
impl<RuntimeCall> Order<RuntimeCall> {
|
||||
pub fn into<C>(self) -> Order<C> {
|
||||
Order::from(self)
|
||||
}
|
||||
pub fn from<C>(order: Order<C>) -> Self {
|
||||
use Order::*;
|
||||
match order {
|
||||
Null => Null,
|
||||
DepositAsset { assets, dest } => DepositAsset { assets, dest },
|
||||
DepositReserveAsset { assets, dest, effects } =>
|
||||
DepositReserveAsset { assets, dest, effects },
|
||||
ExchangeAsset { give, receive } => ExchangeAsset { give, receive },
|
||||
InitiateReserveWithdraw { assets, reserve, effects } =>
|
||||
InitiateReserveWithdraw { assets, reserve, effects },
|
||||
InitiateTeleport { assets, dest, effects } =>
|
||||
InitiateTeleport { assets, dest, effects },
|
||||
QueryHolding { query_id, dest, assets } => QueryHolding { query_id, dest, assets },
|
||||
BuyExecution { fees, weight, debt, halt_on_error, xcm } => {
|
||||
let xcm = xcm.into_iter().map(Xcm::from).collect();
|
||||
BuyExecution { fees, weight, debt, halt_on_error, xcm }
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<RuntimeCall> TryFrom<Order1<RuntimeCall>> for Order<RuntimeCall> {
|
||||
type Error = ();
|
||||
fn try_from(old: Order1<RuntimeCall>) -> result::Result<Order<RuntimeCall>, ()> {
|
||||
use Order::*;
|
||||
Ok(match old {
|
||||
Order1::Noop => Null,
|
||||
Order1::DepositAsset { assets, beneficiary, .. } =>
|
||||
DepositAsset { assets: assets.try_into()?, dest: beneficiary.try_into()? },
|
||||
Order1::DepositReserveAsset { assets, dest, effects, .. } => DepositReserveAsset {
|
||||
assets: assets.try_into()?,
|
||||
dest: dest.try_into()?,
|
||||
effects: effects
|
||||
.into_iter()
|
||||
.map(Order::<()>::try_from)
|
||||
.collect::<result::Result<_, _>>()?,
|
||||
},
|
||||
Order1::ExchangeAsset { give, receive } =>
|
||||
ExchangeAsset { give: give.try_into()?, receive: receive.try_into()? },
|
||||
Order1::InitiateReserveWithdraw { assets, reserve, effects } =>
|
||||
InitiateReserveWithdraw {
|
||||
assets: assets.try_into()?,
|
||||
reserve: reserve.try_into()?,
|
||||
effects: effects
|
||||
.into_iter()
|
||||
.map(Order::<()>::try_from)
|
||||
.collect::<result::Result<_, _>>()?,
|
||||
},
|
||||
Order1::InitiateTeleport { assets, dest, effects } => InitiateTeleport {
|
||||
assets: assets.try_into()?,
|
||||
dest: dest.try_into()?,
|
||||
effects: effects
|
||||
.into_iter()
|
||||
.map(Order::<()>::try_from)
|
||||
.collect::<result::Result<_, _>>()?,
|
||||
},
|
||||
Order1::QueryHolding { query_id, dest, assets } =>
|
||||
QueryHolding { query_id, dest: dest.try_into()?, assets: assets.try_into()? },
|
||||
Order1::BuyExecution { fees, weight, debt, halt_on_error, instructions } => {
|
||||
let xcm = instructions
|
||||
.into_iter()
|
||||
.map(Xcm::<RuntimeCall>::try_from)
|
||||
.collect::<result::Result<_, _>>()?;
|
||||
BuyExecution { fees: fees.try_into()?, weight, debt, halt_on_error, xcm }
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,267 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! Cross-Consensus Message format data structures.
|
||||
|
||||
use core::result;
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
|
||||
use super::{MultiLocation, Xcm};
|
||||
|
||||
#[derive(Clone, Encode, Decode, Eq, PartialEq, Debug, scale_info::TypeInfo)]
|
||||
pub enum Error {
|
||||
Undefined,
|
||||
/// An arithmetic overflow happened.
|
||||
Overflow,
|
||||
/// The operation is intentionally unsupported.
|
||||
Unimplemented,
|
||||
UnhandledXcmVersion,
|
||||
/// The implementation does not handle a given XCM.
|
||||
UnhandledXcmMessage,
|
||||
/// The implementation does not handle an effect present in an XCM.
|
||||
UnhandledEffect,
|
||||
EscalationOfPrivilege,
|
||||
UntrustedReserveLocation,
|
||||
UntrustedTeleportLocation,
|
||||
DestinationBufferOverflow,
|
||||
/// The message and destination was recognized as being reachable but the operation could not be completed.
|
||||
/// A human-readable explanation of the specific issue is provided.
|
||||
SendFailed(#[codec(skip)] &'static str),
|
||||
/// The message and destination combination was not recognized as being reachable.
|
||||
CannotReachDestination(MultiLocation, Xcm<()>),
|
||||
MultiLocationFull,
|
||||
FailedToDecode,
|
||||
BadOrigin,
|
||||
ExceedsMaxMessageSize,
|
||||
/// An asset transaction (like withdraw or deposit) failed.
|
||||
/// See implementers of the `TransactAsset` trait for sources.
|
||||
/// Causes can include type conversion failures between id or balance types.
|
||||
FailedToTransactAsset(#[codec(skip)] &'static str),
|
||||
/// Execution of the XCM would potentially result in a greater weight used than the pre-specified
|
||||
/// weight limit. The amount that is potentially required is the parameter.
|
||||
WeightLimitReached(Weight),
|
||||
/// An asset wildcard was passed where it was not expected (e.g. as the asset to withdraw in a
|
||||
/// `WithdrawAsset` XCM).
|
||||
Wildcard,
|
||||
/// The case where an XCM message has specified a weight limit on an interior call and this
|
||||
/// limit is too low.
|
||||
///
|
||||
/// Used by:
|
||||
/// - `Transact`
|
||||
MaxWeightInvalid,
|
||||
/// The fees specified by the XCM message were not found in the holding account.
|
||||
///
|
||||
/// Used by:
|
||||
/// - `BuyExecution`
|
||||
NotHoldingFees,
|
||||
/// The weight of an XCM message is not computable ahead of execution. This generally means at least part
|
||||
/// of the message is invalid, which could be due to it containing overly nested structures or an invalid
|
||||
/// nested data segment (e.g. for the call in `Transact`).
|
||||
WeightNotComputable,
|
||||
/// The XCM did not pass the barrier condition for execution. The barrier condition differs on different
|
||||
/// chains and in different circumstances, but generally it means that the conditions surrounding the message
|
||||
/// were not such that the chain considers the message worth spending time executing. Since most chains
|
||||
/// lift the barrier to execution on appropriate payment, presentation of an NFT voucher, or based on the
|
||||
/// message origin, it means that none of those were the case.
|
||||
Barrier,
|
||||
/// Indicates that it is not possible for a location to have an asset be withdrawn or transferred from its
|
||||
/// ownership. This probably means it doesn't own (enough of) it, but may also indicate that it is under a
|
||||
/// lock, hold, freeze or is otherwise unavailable.
|
||||
NotWithdrawable,
|
||||
/// Indicates that the consensus system cannot deposit an asset under the ownership of a particular location.
|
||||
LocationCannotHold,
|
||||
/// The assets given to purchase weight is are insufficient for the weight desired.
|
||||
TooExpensive,
|
||||
/// The given asset is not handled.
|
||||
AssetNotFound,
|
||||
/// `execute_xcm` has been called too many times recursively.
|
||||
RecursionLimitReached,
|
||||
}
|
||||
|
||||
impl From<()> for Error {
|
||||
fn from(_: ()) -> Self {
|
||||
Self::Undefined
|
||||
}
|
||||
}
|
||||
|
||||
pub type Result = result::Result<(), Error>;
|
||||
|
||||
/// Local weight type; execution time in picoseconds.
|
||||
pub type Weight = u64;
|
||||
|
||||
/// Outcome of an XCM execution.
|
||||
#[derive(Clone, Encode, Decode, Eq, PartialEq, Debug, scale_info::TypeInfo)]
|
||||
pub enum Outcome {
|
||||
/// Execution completed successfully; given weight was used.
|
||||
Complete(Weight),
|
||||
/// Execution started, but did not complete successfully due to the given error; given weight was used.
|
||||
Incomplete(Weight, Error),
|
||||
/// Execution did not start due to the given error.
|
||||
Error(Error),
|
||||
}
|
||||
|
||||
impl Outcome {
|
||||
pub fn ensure_complete(self) -> Result {
|
||||
match self {
|
||||
Outcome::Complete(_) => Ok(()),
|
||||
Outcome::Incomplete(_, e) => Err(e),
|
||||
Outcome::Error(e) => Err(e),
|
||||
}
|
||||
}
|
||||
pub fn ensure_execution(self) -> result::Result<Weight, Error> {
|
||||
match self {
|
||||
Outcome::Complete(w) => Ok(w),
|
||||
Outcome::Incomplete(w, _) => Ok(w),
|
||||
Outcome::Error(e) => Err(e),
|
||||
}
|
||||
}
|
||||
/// How much weight was used by the XCM execution attempt.
|
||||
pub fn weight_used(&self) -> Weight {
|
||||
match self {
|
||||
Outcome::Complete(w) => *w,
|
||||
Outcome::Incomplete(w, _) => *w,
|
||||
Outcome::Error(_) => 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Type of XCM message executor.
|
||||
pub trait ExecuteXcm<RuntimeCall> {
|
||||
/// Execute some XCM `message` from `origin` using no more than `weight_limit` weight. The weight limit is
|
||||
/// a basic hard-limit and the implementation may place further restrictions or requirements on weight and
|
||||
/// other aspects.
|
||||
fn execute_xcm(
|
||||
origin: MultiLocation,
|
||||
message: Xcm<RuntimeCall>,
|
||||
weight_limit: Weight,
|
||||
) -> Outcome {
|
||||
log::debug!(
|
||||
target: "xcm::execute_xcm",
|
||||
"origin: {:?}, message: {:?}, weight_limit: {:?}",
|
||||
origin,
|
||||
message,
|
||||
weight_limit,
|
||||
);
|
||||
Self::execute_xcm_in_credit(origin, message, weight_limit, 0)
|
||||
}
|
||||
|
||||
/// Execute some XCM `message` from `origin` using no more than `weight_limit` weight.
|
||||
///
|
||||
/// Some amount of `weight_credit` may be provided which, depending on the implementation, may allow
|
||||
/// execution without associated payment.
|
||||
fn execute_xcm_in_credit(
|
||||
origin: MultiLocation,
|
||||
message: Xcm<RuntimeCall>,
|
||||
weight_limit: Weight,
|
||||
weight_credit: Weight,
|
||||
) -> Outcome;
|
||||
}
|
||||
|
||||
impl<C> ExecuteXcm<C> for () {
|
||||
fn execute_xcm_in_credit(
|
||||
_origin: MultiLocation,
|
||||
_message: Xcm<C>,
|
||||
_weight_limit: Weight,
|
||||
_weight_credit: Weight,
|
||||
) -> Outcome {
|
||||
Outcome::Error(Error::Unimplemented)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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`
|
||||
/// might alter the destination and the XCM message for to the next router.
|
||||
///
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use xcm::v0::{MultiLocation, Xcm, Junction, Error, OriginKind, SendXcm, Result};
|
||||
/// # use parity_scale_codec::Encode;
|
||||
///
|
||||
/// /// A sender that only passes the message through and does nothing.
|
||||
/// struct Sender1;
|
||||
/// impl SendXcm for Sender1 {
|
||||
/// fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result {
|
||||
/// return Err(Error::CannotReachDestination(destination, message))
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// /// A sender that accepts a message that has an X2 junction, otherwise stops the routing.
|
||||
/// struct Sender2;
|
||||
/// impl SendXcm for Sender2 {
|
||||
/// fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result {
|
||||
/// if let MultiLocation::X2(j1, j2) = destination {
|
||||
/// Ok(())
|
||||
/// } else {
|
||||
/// Err(Error::Undefined)
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// /// A sender that accepts a message from an X1 parent junction, passing through otherwise.
|
||||
/// struct Sender3;
|
||||
/// impl SendXcm for Sender3 {
|
||||
/// fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result {
|
||||
/// match destination {
|
||||
/// MultiLocation::X1(j) if j == Junction::Parent => Ok(()),
|
||||
/// _ => Err(Error::CannotReachDestination(destination, message)),
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // A call to send via XCM. We don't really care about this.
|
||||
/// # fn main() {
|
||||
/// let call: Vec<u8> = ().encode();
|
||||
/// let message = Xcm::Transact { origin_type: OriginKind::Superuser, require_weight_at_most: 0, call: call.into() };
|
||||
/// let destination = MultiLocation::X1(Junction::Parent);
|
||||
///
|
||||
/// assert!(
|
||||
/// // Sender2 will block this.
|
||||
/// <(Sender1, Sender2, Sender3) as SendXcm>::send_xcm(destination.clone(), message.clone())
|
||||
/// .is_err()
|
||||
/// );
|
||||
///
|
||||
/// assert!(
|
||||
/// // Sender3 will catch this.
|
||||
/// <(Sender1, Sender3) as SendXcm>::send_xcm(destination.clone(), message.clone())
|
||||
/// .is_ok()
|
||||
/// );
|
||||
/// # }
|
||||
/// ```
|
||||
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
|
||||
/// trying other type fields.
|
||||
fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result;
|
||||
}
|
||||
|
||||
#[impl_trait_for_tuples::impl_for_tuples(30)]
|
||||
impl SendXcm for Tuple {
|
||||
fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result {
|
||||
for_tuples!( #(
|
||||
// we shadow `destination` and `message` in each expansion for the next one.
|
||||
let (destination, message) = match Tuple::send_xcm(destination, message) {
|
||||
Err(Error::CannotReachDestination(d, m)) => (d, m),
|
||||
o @ _ => return o,
|
||||
};
|
||||
)* );
|
||||
Err(Error::CannotReachDestination(destination, message))
|
||||
}
|
||||
}
|
||||
@@ -1,518 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! # XCM Version 1
|
||||
//! Version 1 of the Cross-Consensus Message format data structures. The comprehensive list of
|
||||
//! changes can be found in
|
||||
//! [this PR description](https://github.com/paritytech/polkadot/pull/2815#issue-608567900).
|
||||
//!
|
||||
//! ## Changes to be aware of
|
||||
//! Most changes should automatically be resolved via the conversion traits (i.e. `TryFrom` and
|
||||
//! `From`). The list here is mostly for incompatible changes that result in an `Err(())` when
|
||||
//! attempting to convert XCM objects from v0.
|
||||
//!
|
||||
//! ### Junction
|
||||
//! - `v0::Junction::Parent` cannot be converted to v1, because the way we represent parents in v1
|
||||
//! has changed - instead of being a property of the junction, v1 `MultiLocation`s now have an
|
||||
//! extra field representing the number of parents that the `MultiLocation` contains.
|
||||
//!
|
||||
//! ### `MultiLocation`
|
||||
//! - The `try_from` conversion method will always canonicalize the v0 `MultiLocation` before
|
||||
//! attempting to do the proper conversion. Since canonicalization is not a fallible operation,
|
||||
//! we do not expect v0 `MultiLocation` to ever fail to be upgraded to v1.
|
||||
//!
|
||||
//! ### `MultiAsset`
|
||||
//! - Stronger typing to differentiate between a single class of `MultiAsset` and several classes
|
||||
//! of `MultiAssets` is introduced. As the name suggests, a `Vec<MultiAsset>` that is used on all
|
||||
//! APIs will instead be using a new type called `MultiAssets` (note the `s`).
|
||||
//! - All `MultiAsset` variants whose name contains "All" in it, namely `v0::MultiAsset::All`,
|
||||
//! `v0::MultiAsset::AllFungible`, `v0::MultiAsset::AllNonFungible`,
|
||||
//! `v0::MultiAsset::AllAbstractFungible`, `v0::MultiAsset::AllAbstractNonFungible`,
|
||||
//! `v0::MultiAsset::AllConcreteFungible` and `v0::MultiAsset::AllConcreteNonFungible`, will fail
|
||||
//! to convert to v1 `MultiAsset`, since v1 does not contain these variants.
|
||||
//! - Similarly, all `MultiAsset` variants whose name contains "All" in it can be converted into a
|
||||
//! `WildMultiAsset`.
|
||||
//! - `v0::MultiAsset::None` is not represented at all in v1.
|
||||
//!
|
||||
//! ### XCM
|
||||
//! - No special attention necessary
|
||||
//!
|
||||
//! ### Order
|
||||
//! - `v1::Order::DepositAsset` and `v1::Order::DepositReserveAsset` both introduced a new
|
||||
//! `max_asset` field that limits the maximum classes of assets that can be deposited. During
|
||||
//! conversion from v0, the `max_asset` field defaults to 1.
|
||||
//! - v1 Orders that contain `MultiAsset` as argument(s) will need to explicitly specify the amount
|
||||
//! and details of assets. This is to prevent accidental misuse of `All` to possibly transfer,
|
||||
//! spend or otherwise perform unintended operations on `All` assets.
|
||||
//! - v1 Orders that do allow the notion of `All` to be used as wildcards, will instead use a new
|
||||
//! type called `MultiAssetFilter`.
|
||||
|
||||
use super::{
|
||||
v0::{Response as OldResponse, Xcm as OldXcm},
|
||||
v2::{Instruction, Response as NewResponse, Xcm as NewXcm},
|
||||
};
|
||||
use crate::DoubleEncoded;
|
||||
use alloc::vec::Vec;
|
||||
use core::{fmt::Debug, result};
|
||||
use derivative::Derivative;
|
||||
use parity_scale_codec::{self, Decode, Encode};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
mod junction;
|
||||
mod multiasset;
|
||||
mod multilocation;
|
||||
mod order;
|
||||
mod traits; // the new multiasset.
|
||||
|
||||
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 order::Order;
|
||||
pub use traits::{Error, ExecuteXcm, Outcome, Result, SendXcm};
|
||||
|
||||
// These parts of XCM v0 have been unchanged in XCM v1, and are re-imported here.
|
||||
pub use super::v0::{BodyId, BodyPart, NetworkId, OriginKind};
|
||||
|
||||
/// A prelude for importing all types typically used when interacting with XCM messages.
|
||||
pub mod prelude {
|
||||
pub use super::{
|
||||
junction::Junction::{self, *},
|
||||
opaque,
|
||||
order::Order::{self, *},
|
||||
Ancestor, AncestorThen,
|
||||
AssetId::{self, *},
|
||||
AssetInstance::{self, *},
|
||||
BodyId, BodyPart, Error as XcmError, ExecuteXcm,
|
||||
Fungibility::{self, *},
|
||||
InteriorMultiLocation,
|
||||
Junctions::{self, *},
|
||||
MultiAsset,
|
||||
MultiAssetFilter::{self, *},
|
||||
MultiAssets, MultiLocation,
|
||||
NetworkId::{self, *},
|
||||
OriginKind, Outcome, Parent, ParentThen, Response, Result as XcmResult, SendXcm,
|
||||
WildFungibility::{self, Fungible as WildFungible, NonFungible as WildNonFungible},
|
||||
WildMultiAsset::{self, *},
|
||||
Xcm::{self, *},
|
||||
};
|
||||
}
|
||||
|
||||
/// Response data to a query.
|
||||
#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)]
|
||||
pub enum Response {
|
||||
/// Some assets.
|
||||
Assets(MultiAssets),
|
||||
/// An XCM version.
|
||||
Version(super::Version),
|
||||
}
|
||||
|
||||
/// Cross-Consensus Message: A message from one consensus system to another.
|
||||
///
|
||||
/// Consensus systems that may send and receive messages include blockchains and smart contracts.
|
||||
///
|
||||
/// All messages are delivered from a known *origin*, expressed as a `MultiLocation`.
|
||||
///
|
||||
/// This is the inner XCM format and is version-sensitive. Messages are typically passed using the outer
|
||||
/// XCM format, known as `VersionedXcm`.
|
||||
#[derive(Derivative, Encode, Decode, TypeInfo)]
|
||||
#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
|
||||
#[codec(encode_bound())]
|
||||
#[codec(decode_bound())]
|
||||
#[scale_info(bounds(), skip_type_params(RuntimeCall))]
|
||||
pub enum Xcm<RuntimeCall> {
|
||||
/// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into `holding`. Execute the
|
||||
/// orders (`effects`).
|
||||
///
|
||||
/// - `assets`: The asset(s) to be withdrawn into holding.
|
||||
/// - `effects`: The order(s) to execute on the holding register.
|
||||
///
|
||||
/// Kind: *Instruction*.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 0)]
|
||||
WithdrawAsset { assets: MultiAssets, effects: Vec<Order<RuntimeCall>> },
|
||||
|
||||
/// Asset(s) (`assets`) have been received into the ownership of this system on the `origin` system.
|
||||
///
|
||||
/// Some orders are given (`effects`) which should be executed once the corresponding derivative assets have
|
||||
/// been placed into `holding`.
|
||||
///
|
||||
/// - `assets`: The asset(s) that are minted into holding.
|
||||
/// - `effects`: The order(s) to execute on the holding register.
|
||||
///
|
||||
/// Safety: `origin` must be trusted to have received and be storing `assets` such that they may later be
|
||||
/// withdrawn should this system send a corresponding message.
|
||||
///
|
||||
/// Kind: *Trusted Indication*.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 1)]
|
||||
ReserveAssetDeposited { assets: MultiAssets, effects: Vec<Order<RuntimeCall>> },
|
||||
|
||||
/// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets should be
|
||||
/// created on this system.
|
||||
///
|
||||
/// Some orders are given (`effects`) which should be executed once the corresponding derivative assets have
|
||||
/// been placed into the Holding Register.
|
||||
///
|
||||
/// - `assets`: The asset(s) that are minted into the Holding Register.
|
||||
/// - `effects`: The order(s) to execute on the Holding Register.
|
||||
///
|
||||
/// Safety: `origin` must be trusted to have irrevocably destroyed the corresponding `assets` prior as a consequence
|
||||
/// of sending this message.
|
||||
///
|
||||
/// Kind: *Trusted Indication*.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 2)]
|
||||
ReceiveTeleportedAsset { assets: MultiAssets, effects: Vec<Order<RuntimeCall>> },
|
||||
|
||||
/// Indication of the contents of the holding register corresponding to the `QueryHolding` order of `query_id`.
|
||||
///
|
||||
/// - `query_id`: The identifier of the query that resulted in this message being sent.
|
||||
/// - `assets`: The message content.
|
||||
///
|
||||
/// Safety: No concerns.
|
||||
///
|
||||
/// Kind: *Information*.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 3)]
|
||||
QueryResponse {
|
||||
#[codec(compact)]
|
||||
query_id: u64,
|
||||
response: Response,
|
||||
},
|
||||
|
||||
/// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets under the
|
||||
/// ownership of `beneficiary`.
|
||||
///
|
||||
/// - `assets`: The asset(s) to be withdrawn.
|
||||
/// - `beneficiary`: The new owner for the assets.
|
||||
///
|
||||
/// Safety: No concerns.
|
||||
///
|
||||
/// Kind: *Instruction*.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 4)]
|
||||
TransferAsset { assets: MultiAssets, beneficiary: MultiLocation },
|
||||
|
||||
/// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets under the
|
||||
/// ownership of `dest` within this consensus system (i.e. its sovereign account).
|
||||
///
|
||||
/// Send an onward XCM message to `dest` of `ReserveAssetDeposited` with the given `effects`.
|
||||
///
|
||||
/// - `assets`: The asset(s) to be withdrawn.
|
||||
/// - `dest`: The location whose sovereign account will own the assets and thus the effective beneficiary for the
|
||||
/// assets and the notification target for the reserve asset deposit message.
|
||||
/// - `effects`: The orders that should be contained in the `ReserveAssetDeposited` which is sent onwards to
|
||||
/// `dest`.
|
||||
///
|
||||
/// Safety: No concerns.
|
||||
///
|
||||
/// Kind: *Instruction*.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 5)]
|
||||
TransferReserveAsset { assets: MultiAssets, dest: MultiLocation, effects: Vec<Order<()>> },
|
||||
|
||||
/// Apply the encoded transaction `call`, whose dispatch-origin should be `origin` as expressed by the kind
|
||||
/// of origin `origin_type`.
|
||||
///
|
||||
/// - `origin_type`: The means of expressing the message origin as a dispatch origin.
|
||||
/// - `max_weight`: The weight of `call`; this should be at least the chain's calculated weight and will
|
||||
/// be used in the weight determination arithmetic.
|
||||
/// - `call`: The encoded transaction to be applied.
|
||||
///
|
||||
/// Safety: No concerns.
|
||||
///
|
||||
/// Kind: *Instruction*.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 6)]
|
||||
Transact {
|
||||
origin_type: OriginKind,
|
||||
require_weight_at_most: u64,
|
||||
call: DoubleEncoded<RuntimeCall>,
|
||||
},
|
||||
|
||||
/// A message to notify about a new incoming HRMP channel. This message is meant to be sent by the
|
||||
/// relay-chain to a para.
|
||||
///
|
||||
/// - `sender`: The sender in the to-be opened channel. Also, the initiator of the channel opening.
|
||||
/// - `max_message_size`: The maximum size of a message proposed by the sender.
|
||||
/// - `max_capacity`: The maximum number of messages that can be queued in the channel.
|
||||
///
|
||||
/// Safety: The message should originate directly from the relay-chain.
|
||||
///
|
||||
/// Kind: *System Notification*
|
||||
#[codec(index = 7)]
|
||||
HrmpNewChannelOpenRequest {
|
||||
#[codec(compact)]
|
||||
sender: u32,
|
||||
#[codec(compact)]
|
||||
max_message_size: u32,
|
||||
#[codec(compact)]
|
||||
max_capacity: u32,
|
||||
},
|
||||
|
||||
/// A message to notify about that a previously sent open channel request has been accepted by
|
||||
/// the recipient. That means that the channel will be opened during the next relay-chain session
|
||||
/// change. This message is meant to be sent by the relay-chain to a para.
|
||||
///
|
||||
/// Safety: The message should originate directly from the relay-chain.
|
||||
///
|
||||
/// Kind: *System Notification*
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 8)]
|
||||
HrmpChannelAccepted {
|
||||
#[codec(compact)]
|
||||
recipient: u32,
|
||||
},
|
||||
|
||||
/// A message to notify that the other party in an open channel decided to close it. In particular,
|
||||
/// `initiator` is going to close the channel opened from `sender` to the `recipient`. The close
|
||||
/// will be enacted at the next relay-chain session change. This message is meant to be sent by
|
||||
/// the relay-chain to a para.
|
||||
///
|
||||
/// Safety: The message should originate directly from the relay-chain.
|
||||
///
|
||||
/// Kind: *System Notification*
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 9)]
|
||||
HrmpChannelClosing {
|
||||
#[codec(compact)]
|
||||
initiator: u32,
|
||||
#[codec(compact)]
|
||||
sender: u32,
|
||||
#[codec(compact)]
|
||||
recipient: u32,
|
||||
},
|
||||
|
||||
/// A message to indicate that the embedded XCM is actually arriving on behalf of some consensus
|
||||
/// location within the origin.
|
||||
///
|
||||
/// Kind: *Instruction*
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 10)]
|
||||
RelayedFrom { who: InteriorMultiLocation, message: alloc::boxed::Box<Xcm<RuntimeCall>> },
|
||||
|
||||
/// Ask the destination system to respond with the most recent version of XCM that they
|
||||
/// support in a `QueryResponse` instruction. Any changes to this should also elicit similar
|
||||
/// responses when they happen.
|
||||
///
|
||||
/// Kind: *Instruction*
|
||||
#[codec(index = 11)]
|
||||
SubscribeVersion {
|
||||
#[codec(compact)]
|
||||
query_id: u64,
|
||||
#[codec(compact)]
|
||||
max_response_weight: u64,
|
||||
},
|
||||
|
||||
/// Cancel the effect of a previous `SubscribeVersion` instruction.
|
||||
///
|
||||
/// Kind: *Instruction*
|
||||
#[codec(index = 12)]
|
||||
UnsubscribeVersion,
|
||||
}
|
||||
|
||||
impl<RuntimeCall> Xcm<RuntimeCall> {
|
||||
pub fn into<C>(self) -> Xcm<C> {
|
||||
Xcm::from(self)
|
||||
}
|
||||
pub fn from<C>(xcm: Xcm<C>) -> Self {
|
||||
use Xcm::*;
|
||||
match xcm {
|
||||
WithdrawAsset { assets, effects } =>
|
||||
WithdrawAsset { assets, effects: effects.into_iter().map(Order::into).collect() },
|
||||
ReserveAssetDeposited { assets, effects } => ReserveAssetDeposited {
|
||||
assets,
|
||||
effects: effects.into_iter().map(Order::into).collect(),
|
||||
},
|
||||
ReceiveTeleportedAsset { assets, effects } => ReceiveTeleportedAsset {
|
||||
assets,
|
||||
effects: effects.into_iter().map(Order::into).collect(),
|
||||
},
|
||||
QueryResponse { query_id, response } => QueryResponse { query_id, response },
|
||||
TransferAsset { assets, beneficiary } => TransferAsset { assets, beneficiary },
|
||||
TransferReserveAsset { assets, dest, effects } =>
|
||||
TransferReserveAsset { assets, dest, effects },
|
||||
HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
|
||||
HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
|
||||
HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient },
|
||||
HrmpChannelClosing { initiator, sender, recipient } =>
|
||||
HrmpChannelClosing { initiator, sender, recipient },
|
||||
Transact { origin_type, require_weight_at_most, call } =>
|
||||
Transact { origin_type, require_weight_at_most, call: call.into() },
|
||||
RelayedFrom { who, message } =>
|
||||
RelayedFrom { who, message: alloc::boxed::Box::new((*message).into()) },
|
||||
SubscribeVersion { query_id, max_response_weight } =>
|
||||
SubscribeVersion { query_id, max_response_weight },
|
||||
UnsubscribeVersion => UnsubscribeVersion,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod opaque {
|
||||
/// The basic concrete type of `generic::Xcm`, which doesn't make any assumptions about the format of a
|
||||
/// call other than it is pre-encoded.
|
||||
pub type Xcm = super::Xcm<()>;
|
||||
|
||||
pub use super::order::opaque::*;
|
||||
}
|
||||
|
||||
// Convert from a v0 response to a v1 response
|
||||
impl TryFrom<OldResponse> for Response {
|
||||
type Error = ();
|
||||
fn try_from(old_response: OldResponse) -> result::Result<Self, ()> {
|
||||
match old_response {
|
||||
OldResponse::Assets(assets) => Ok(Self::Assets(assets.try_into()?)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<RuntimeCall> TryFrom<OldXcm<RuntimeCall>> for Xcm<RuntimeCall> {
|
||||
type Error = ();
|
||||
fn try_from(old: OldXcm<RuntimeCall>) -> result::Result<Xcm<RuntimeCall>, ()> {
|
||||
use Xcm::*;
|
||||
Ok(match old {
|
||||
OldXcm::WithdrawAsset { assets, effects } => WithdrawAsset {
|
||||
assets: assets.try_into()?,
|
||||
effects: effects
|
||||
.into_iter()
|
||||
.map(Order::try_from)
|
||||
.collect::<result::Result<_, _>>()?,
|
||||
},
|
||||
OldXcm::ReserveAssetDeposit { assets, effects } => ReserveAssetDeposited {
|
||||
assets: assets.try_into()?,
|
||||
effects: effects
|
||||
.into_iter()
|
||||
.map(Order::try_from)
|
||||
.collect::<result::Result<_, _>>()?,
|
||||
},
|
||||
OldXcm::TeleportAsset { assets, effects } => ReceiveTeleportedAsset {
|
||||
assets: assets.try_into()?,
|
||||
effects: effects
|
||||
.into_iter()
|
||||
.map(Order::try_from)
|
||||
.collect::<result::Result<_, _>>()?,
|
||||
},
|
||||
OldXcm::QueryResponse { query_id, response } =>
|
||||
QueryResponse { query_id, response: response.try_into()? },
|
||||
OldXcm::TransferAsset { assets, dest } =>
|
||||
TransferAsset { assets: assets.try_into()?, beneficiary: dest.try_into()? },
|
||||
OldXcm::TransferReserveAsset { assets, dest, effects } => TransferReserveAsset {
|
||||
assets: assets.try_into()?,
|
||||
dest: dest.try_into()?,
|
||||
effects: effects
|
||||
.into_iter()
|
||||
.map(Order::try_from)
|
||||
.collect::<result::Result<_, _>>()?,
|
||||
},
|
||||
OldXcm::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
|
||||
HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
|
||||
OldXcm::HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient },
|
||||
OldXcm::HrmpChannelClosing { initiator, sender, recipient } =>
|
||||
HrmpChannelClosing { initiator, sender, recipient },
|
||||
OldXcm::Transact { origin_type, require_weight_at_most, call } =>
|
||||
Transact { origin_type, require_weight_at_most, call: call.into() },
|
||||
OldXcm::RelayedFrom { who, message } => RelayedFrom {
|
||||
who: MultiLocation::try_from(who)?.try_into()?,
|
||||
message: alloc::boxed::Box::new((*message).try_into()?),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<RuntimeCall> TryFrom<NewXcm<RuntimeCall>> for Xcm<RuntimeCall> {
|
||||
type Error = ();
|
||||
fn try_from(old: NewXcm<RuntimeCall>) -> result::Result<Xcm<RuntimeCall>, ()> {
|
||||
use Xcm::*;
|
||||
let mut iter = old.0.into_iter();
|
||||
let instruction = iter.next().ok_or(())?;
|
||||
Ok(match instruction {
|
||||
Instruction::WithdrawAsset(assets) => {
|
||||
let effects = iter.map(Order::try_from).collect::<result::Result<_, _>>()?;
|
||||
WithdrawAsset { assets, effects }
|
||||
},
|
||||
Instruction::ReserveAssetDeposited(assets) => {
|
||||
if !matches!(iter.next(), Some(Instruction::ClearOrigin)) {
|
||||
return Err(())
|
||||
}
|
||||
let effects = iter.map(Order::try_from).collect::<result::Result<_, _>>()?;
|
||||
ReserveAssetDeposited { assets, effects }
|
||||
},
|
||||
Instruction::ReceiveTeleportedAsset(assets) => {
|
||||
if !matches!(iter.next(), Some(Instruction::ClearOrigin)) {
|
||||
return Err(())
|
||||
}
|
||||
let effects = iter.map(Order::try_from).collect::<result::Result<_, _>>()?;
|
||||
ReceiveTeleportedAsset { assets, effects }
|
||||
},
|
||||
Instruction::QueryResponse { query_id, response, max_weight } => {
|
||||
// Cannot handle special response weights.
|
||||
if max_weight > 0 {
|
||||
return Err(())
|
||||
}
|
||||
QueryResponse { query_id, response: response.try_into()? }
|
||||
},
|
||||
Instruction::TransferAsset { assets, beneficiary } =>
|
||||
TransferAsset { assets, beneficiary },
|
||||
Instruction::TransferReserveAsset { assets, dest, xcm } => TransferReserveAsset {
|
||||
assets,
|
||||
dest,
|
||||
effects: xcm
|
||||
.0
|
||||
.into_iter()
|
||||
.map(Order::try_from)
|
||||
.collect::<result::Result<_, _>>()?,
|
||||
},
|
||||
Instruction::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
|
||||
HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
|
||||
Instruction::HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient },
|
||||
Instruction::HrmpChannelClosing { initiator, sender, recipient } =>
|
||||
HrmpChannelClosing { initiator, sender, recipient },
|
||||
Instruction::Transact { origin_type, require_weight_at_most, call } =>
|
||||
Transact { origin_type, require_weight_at_most, call },
|
||||
Instruction::SubscribeVersion { query_id, max_response_weight } =>
|
||||
SubscribeVersion { query_id, max_response_weight },
|
||||
Instruction::UnsubscribeVersion => UnsubscribeVersion,
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Convert from a v1 response to a v2 response
|
||||
impl TryFrom<NewResponse> for Response {
|
||||
type Error = ();
|
||||
fn try_from(response: NewResponse) -> result::Result<Self, ()> {
|
||||
match response {
|
||||
NewResponse::Assets(assets) => Ok(Self::Assets(assets)),
|
||||
NewResponse::Version(version) => Ok(Self::Version(version)),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,292 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! Version 1 of the Cross-Consensus Message format data structures.
|
||||
|
||||
use super::{MultiAsset, MultiAssetFilter, MultiAssets, MultiLocation, Xcm};
|
||||
use crate::{v0::Order as OldOrder, v2::Instruction};
|
||||
use alloc::{vec, vec::Vec};
|
||||
use core::result;
|
||||
use derivative::Derivative;
|
||||
use parity_scale_codec::{self, Decode, Encode};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
/// An instruction to be executed on some or all of the assets in holding, used by asset-related XCM messages.
|
||||
#[derive(Derivative, Encode, Decode, TypeInfo)]
|
||||
#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
|
||||
#[codec(encode_bound())]
|
||||
#[codec(decode_bound())]
|
||||
#[scale_info(bounds(), skip_type_params(RuntimeCall))]
|
||||
pub enum Order<RuntimeCall> {
|
||||
/// Do nothing. Not generally used.
|
||||
#[codec(index = 0)]
|
||||
Noop,
|
||||
|
||||
/// Remove the asset(s) (`assets`) from holding and place equivalent assets under the ownership of `beneficiary`
|
||||
/// within this consensus system.
|
||||
///
|
||||
/// - `assets`: The asset(s) to remove from holding.
|
||||
/// - `max_assets`: The maximum number of unique assets/asset instances to remove from holding. Only the first
|
||||
/// `max_assets` assets/instances of those matched by `assets` will be removed, prioritized under standard asset
|
||||
/// ordering. Any others will remain in holding.
|
||||
/// - `beneficiary`: The new owner for the assets.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 1)]
|
||||
DepositAsset { assets: MultiAssetFilter, max_assets: u32, beneficiary: MultiLocation },
|
||||
|
||||
/// Remove the asset(s) (`assets`) from holding and place equivalent assets under the ownership of `dest` within
|
||||
/// this consensus system (i.e. its sovereign account).
|
||||
///
|
||||
/// Send an onward XCM message to `dest` of `ReserveAssetDeposited` with the given `effects`.
|
||||
///
|
||||
/// - `assets`: The asset(s) to remove from holding.
|
||||
/// - `max_assets`: The maximum number of unique assets/asset instances to remove from holding. Only the first
|
||||
/// `max_assets` assets/instances of those matched by `assets` will be removed, prioritized under standard asset
|
||||
/// ordering. Any others will remain in holding.
|
||||
/// - `dest`: The location whose sovereign account will own the assets and thus the effective beneficiary for the
|
||||
/// assets and the notification target for the reserve asset deposit message.
|
||||
/// - `effects`: The orders that should be contained in the `ReserveAssetDeposited` which is sent onwards to
|
||||
/// `dest`.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 2)]
|
||||
DepositReserveAsset {
|
||||
assets: MultiAssetFilter,
|
||||
max_assets: u32,
|
||||
dest: MultiLocation,
|
||||
effects: Vec<Order<()>>,
|
||||
},
|
||||
|
||||
/// Remove the asset(s) (`give`) from holding and replace them with alternative assets.
|
||||
///
|
||||
/// The minimum amount of assets to be received into holding for the order not to fail may be stated.
|
||||
///
|
||||
/// - `give`: The asset(s) to remove from holding.
|
||||
/// - `receive`: The minimum amount of assets(s) which `give` should be exchanged for.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 3)]
|
||||
ExchangeAsset { give: MultiAssetFilter, receive: MultiAssets },
|
||||
|
||||
/// Remove the asset(s) (`assets`) from holding and send a `WithdrawAsset` XCM message to a reserve location.
|
||||
///
|
||||
/// - `assets`: The asset(s) to remove from holding.
|
||||
/// - `reserve`: A valid location that acts as a reserve for all asset(s) in `assets`. The sovereign account
|
||||
/// of this consensus system *on the reserve location* will have appropriate assets withdrawn and `effects` will
|
||||
/// be executed on them. There will typically be only one valid location on any given asset/chain combination.
|
||||
/// - `effects`: The orders to execute on the assets once withdrawn *on the reserve location*.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 4)]
|
||||
InitiateReserveWithdraw {
|
||||
assets: MultiAssetFilter,
|
||||
reserve: MultiLocation,
|
||||
effects: Vec<Order<()>>,
|
||||
},
|
||||
|
||||
/// Remove the asset(s) (`assets`) from holding and send a `ReceiveTeleportedAsset` XCM message to a `destination`
|
||||
/// location.
|
||||
///
|
||||
/// - `assets`: The asset(s) to remove from holding.
|
||||
/// - `destination`: A valid location that has a bi-lateral teleportation arrangement.
|
||||
/// - `effects`: The orders to execute on the assets once arrived *on the destination location*.
|
||||
///
|
||||
/// NOTE: The `destination` location *MUST* respect this origin as a valid teleportation origin for all `assets`.
|
||||
/// If it does not, then the assets may be lost.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 5)]
|
||||
InitiateTeleport { assets: MultiAssetFilter, dest: MultiLocation, effects: Vec<Order<()>> },
|
||||
|
||||
/// Send a `Balances` XCM message with the `assets` value equal to the holding contents, or a portion thereof.
|
||||
///
|
||||
/// - `query_id`: An identifier that will be replicated into the returned XCM message.
|
||||
/// - `dest`: A valid destination for the returned XCM message. This may be limited to the current origin.
|
||||
/// - `assets`: A filter for the assets that should be reported back. The assets reported back will be, asset-
|
||||
/// wise, *the lesser of this value and the holding register*. No wildcards will be used when reporting assets
|
||||
/// back.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 6)]
|
||||
QueryHolding {
|
||||
#[codec(compact)]
|
||||
query_id: u64,
|
||||
dest: MultiLocation,
|
||||
assets: MultiAssetFilter,
|
||||
},
|
||||
|
||||
/// Pay for the execution of some XCM `instructions` and `orders` with up to `weight` picoseconds of execution time,
|
||||
/// paying for this with up to `fees` from the Holding Register.
|
||||
///
|
||||
/// - `fees`: The asset(s) to remove from holding to pay for fees.
|
||||
/// - `weight`: The amount of weight to purchase; this should be at least the shallow weight of `effects` and `xcm`.
|
||||
/// - `debt`: The amount of weight-debt already incurred to be paid off; this should be equal to the unpaid weight of
|
||||
/// any surrounding operations/orders.
|
||||
/// - `halt_on_error`: If `true`, the execution of the `orders` and `operations` will halt on the first failure. If
|
||||
/// `false`, then execution will continue regardless.
|
||||
/// - `instructions`: XCM instructions to be executed outside of the context of the current Holding Register;
|
||||
/// execution of these instructions happens AFTER the execution of the `orders`. The (shallow) weight for these
|
||||
/// must be paid for with the `weight` purchased.
|
||||
/// Errors:
|
||||
#[codec(index = 7)]
|
||||
BuyExecution {
|
||||
fees: MultiAsset,
|
||||
weight: u64,
|
||||
debt: u64,
|
||||
halt_on_error: bool,
|
||||
instructions: Vec<Xcm<RuntimeCall>>,
|
||||
},
|
||||
}
|
||||
|
||||
pub mod opaque {
|
||||
pub type Order = super::Order<()>;
|
||||
}
|
||||
|
||||
impl<RuntimeCall> Order<RuntimeCall> {
|
||||
pub fn into<C>(self) -> Order<C> {
|
||||
Order::from(self)
|
||||
}
|
||||
pub fn from<C>(order: Order<C>) -> Self {
|
||||
use Order::*;
|
||||
match order {
|
||||
Noop => Noop,
|
||||
DepositAsset { assets, max_assets, beneficiary } =>
|
||||
DepositAsset { assets, max_assets, beneficiary },
|
||||
DepositReserveAsset { assets, max_assets, dest, effects } =>
|
||||
DepositReserveAsset { assets, max_assets, dest, effects },
|
||||
ExchangeAsset { give, receive } => ExchangeAsset { give, receive },
|
||||
InitiateReserveWithdraw { assets, reserve, effects } =>
|
||||
InitiateReserveWithdraw { assets, reserve, effects },
|
||||
InitiateTeleport { assets, dest, effects } =>
|
||||
InitiateTeleport { assets, dest, effects },
|
||||
QueryHolding { query_id, dest, assets } => QueryHolding { query_id, dest, assets },
|
||||
BuyExecution { fees, weight, debt, halt_on_error, instructions } => {
|
||||
let instructions = instructions.into_iter().map(Xcm::from).collect();
|
||||
BuyExecution { fees, weight, debt, halt_on_error, instructions }
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<RuntimeCall> TryFrom<OldOrder<RuntimeCall>> for Order<RuntimeCall> {
|
||||
type Error = ();
|
||||
fn try_from(old: OldOrder<RuntimeCall>) -> result::Result<Order<RuntimeCall>, ()> {
|
||||
use Order::*;
|
||||
Ok(match old {
|
||||
OldOrder::Null => Noop,
|
||||
OldOrder::DepositAsset { assets, dest } => DepositAsset {
|
||||
assets: assets.try_into()?,
|
||||
max_assets: 1,
|
||||
beneficiary: dest.try_into()?,
|
||||
},
|
||||
OldOrder::DepositReserveAsset { assets, dest, effects } => DepositReserveAsset {
|
||||
assets: assets.try_into()?,
|
||||
max_assets: 1,
|
||||
dest: dest.try_into()?,
|
||||
effects: effects
|
||||
.into_iter()
|
||||
.map(Order::<()>::try_from)
|
||||
.collect::<result::Result<_, _>>()?,
|
||||
},
|
||||
OldOrder::ExchangeAsset { give, receive } =>
|
||||
ExchangeAsset { give: give.try_into()?, receive: receive.try_into()? },
|
||||
OldOrder::InitiateReserveWithdraw { assets, reserve, effects } =>
|
||||
InitiateReserveWithdraw {
|
||||
assets: assets.try_into()?,
|
||||
reserve: reserve.try_into()?,
|
||||
effects: effects
|
||||
.into_iter()
|
||||
.map(Order::<()>::try_from)
|
||||
.collect::<result::Result<_, _>>()?,
|
||||
},
|
||||
OldOrder::InitiateTeleport { assets, dest, effects } => InitiateTeleport {
|
||||
assets: assets.try_into()?,
|
||||
dest: dest.try_into()?,
|
||||
effects: effects
|
||||
.into_iter()
|
||||
.map(Order::<()>::try_from)
|
||||
.collect::<result::Result<_, _>>()?,
|
||||
},
|
||||
OldOrder::QueryHolding { query_id, dest, assets } =>
|
||||
QueryHolding { query_id, dest: dest.try_into()?, assets: assets.try_into()? },
|
||||
OldOrder::BuyExecution { fees, weight, debt, halt_on_error, xcm } => {
|
||||
let instructions = xcm
|
||||
.into_iter()
|
||||
.map(Xcm::<RuntimeCall>::try_from)
|
||||
.collect::<result::Result<_, _>>()?;
|
||||
BuyExecution { fees: fees.try_into()?, weight, debt, halt_on_error, instructions }
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<RuntimeCall> TryFrom<Instruction<RuntimeCall>> for Order<RuntimeCall> {
|
||||
type Error = ();
|
||||
fn try_from(old: Instruction<RuntimeCall>) -> result::Result<Order<RuntimeCall>, ()> {
|
||||
use Order::*;
|
||||
Ok(match old {
|
||||
Instruction::DepositAsset { assets, max_assets, beneficiary } =>
|
||||
DepositAsset { assets, max_assets, beneficiary },
|
||||
Instruction::DepositReserveAsset { assets, max_assets, dest, xcm } =>
|
||||
DepositReserveAsset {
|
||||
assets,
|
||||
max_assets,
|
||||
dest,
|
||||
effects: xcm
|
||||
.0
|
||||
.into_iter()
|
||||
.map(Order::<()>::try_from)
|
||||
.collect::<result::Result<_, _>>()?,
|
||||
},
|
||||
Instruction::ExchangeAsset { give, receive } => ExchangeAsset { give, receive },
|
||||
Instruction::InitiateReserveWithdraw { assets, reserve, xcm } =>
|
||||
InitiateReserveWithdraw {
|
||||
assets,
|
||||
reserve,
|
||||
effects: xcm
|
||||
.0
|
||||
.into_iter()
|
||||
.map(Order::<()>::try_from)
|
||||
.collect::<result::Result<_, _>>()?,
|
||||
},
|
||||
Instruction::InitiateTeleport { assets, dest, xcm } => InitiateTeleport {
|
||||
assets,
|
||||
dest,
|
||||
effects: xcm
|
||||
.0
|
||||
.into_iter()
|
||||
.map(Order::<()>::try_from)
|
||||
.collect::<result::Result<_, _>>()?,
|
||||
},
|
||||
Instruction::QueryHolding { query_id, dest, assets, max_response_weight } => {
|
||||
// Cannot handle special response weights.
|
||||
if max_response_weight > 0 {
|
||||
return Err(())
|
||||
}
|
||||
QueryHolding { query_id, dest, assets }
|
||||
},
|
||||
Instruction::BuyExecution { fees, weight_limit } => {
|
||||
let instructions = vec![];
|
||||
let halt_on_error = true;
|
||||
let weight = 0;
|
||||
let debt = Option::<u64>::from(weight_limit).ok_or(())?;
|
||||
BuyExecution { fees, weight, debt, halt_on_error, instructions }
|
||||
},
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,277 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! Cross-Consensus Message format data structures.
|
||||
|
||||
use core::result;
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
use super::{MultiLocation, Xcm};
|
||||
|
||||
#[derive(Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)]
|
||||
pub enum Error {
|
||||
Undefined,
|
||||
/// An arithmetic overflow happened.
|
||||
Overflow,
|
||||
/// The operation is intentionally unsupported.
|
||||
Unimplemented,
|
||||
UnhandledXcmVersion,
|
||||
/// The implementation does not handle a given XCM.
|
||||
UnhandledXcmMessage,
|
||||
/// The implementation does not handle an effect present in an XCM.
|
||||
UnhandledEffect,
|
||||
EscalationOfPrivilege,
|
||||
UntrustedReserveLocation,
|
||||
UntrustedTeleportLocation,
|
||||
DestinationBufferOverflow,
|
||||
/// The message and destination was recognized as being reachable but the operation could not be completed.
|
||||
/// A human-readable explanation of the specific issue is provided.
|
||||
SendFailed(#[codec(skip)] &'static str),
|
||||
/// The message and destination combination was not recognized as being reachable.
|
||||
CannotReachDestination(MultiLocation, Xcm<()>),
|
||||
MultiLocationFull,
|
||||
FailedToDecode,
|
||||
BadOrigin,
|
||||
ExceedsMaxMessageSize,
|
||||
/// An asset transaction (like withdraw or deposit) failed.
|
||||
/// See implementers of the `TransactAsset` trait for sources.
|
||||
/// Causes can include type conversion failures between id or balance types.
|
||||
FailedToTransactAsset(#[codec(skip)] &'static str),
|
||||
/// Execution of the XCM would potentially result in a greater weight used than the pre-specified
|
||||
/// weight limit. The amount that is potentially required is the parameter.
|
||||
WeightLimitReached(Weight),
|
||||
/// An asset wildcard was passed where it was not expected (e.g. as the asset to withdraw in a
|
||||
/// `WithdrawAsset` XCM).
|
||||
Wildcard,
|
||||
/// The case where an XCM message has specified a weight limit on an interior call and this
|
||||
/// limit is too low.
|
||||
///
|
||||
/// Used by:
|
||||
/// - `Transact`
|
||||
MaxWeightInvalid,
|
||||
/// The fees specified by the XCM message were not found in the holding register.
|
||||
///
|
||||
/// Used by:
|
||||
/// - `BuyExecution`
|
||||
NotHoldingFees,
|
||||
/// The weight of an XCM message is not computable ahead of execution. This generally means at least part
|
||||
/// of the message is invalid, which could be due to it containing overly nested structures or an invalid
|
||||
/// nested data segment (e.g. for the call in `Transact`).
|
||||
WeightNotComputable,
|
||||
/// The XCM did not pass the barrier condition for execution. The barrier condition differs on different
|
||||
/// chains and in different circumstances, but generally it means that the conditions surrounding the message
|
||||
/// were not such that the chain considers the message worth spending time executing. Since most chains
|
||||
/// lift the barrier to execution on appropriate payment, presentation of an NFT voucher, or based on the
|
||||
/// message origin, it means that none of those were the case.
|
||||
Barrier,
|
||||
/// Indicates that it is not possible for a location to have an asset be withdrawn or transferred from its
|
||||
/// ownership. This probably means it doesn't own (enough of) it, but may also indicate that it is under a
|
||||
/// lock, hold, freeze or is otherwise unavailable.
|
||||
NotWithdrawable,
|
||||
/// Indicates that the consensus system cannot deposit an asset under the ownership of a particular location.
|
||||
LocationCannotHold,
|
||||
/// The assets given to purchase weight is are insufficient for the weight desired.
|
||||
TooExpensive,
|
||||
/// The given asset is not handled.
|
||||
AssetNotFound,
|
||||
/// The given message cannot be translated into a format that the destination can be expected to interpret.
|
||||
DestinationUnsupported,
|
||||
/// `execute_xcm` has been called too many times recursively.
|
||||
RecursionLimitReached,
|
||||
}
|
||||
|
||||
impl From<()> for Error {
|
||||
fn from(_: ()) -> Self {
|
||||
Self::Undefined
|
||||
}
|
||||
}
|
||||
|
||||
pub type Result = result::Result<(), Error>;
|
||||
|
||||
/// Local weight type; execution time in picoseconds.
|
||||
pub type Weight = u64;
|
||||
|
||||
/// Outcome of an XCM execution.
|
||||
#[derive(Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)]
|
||||
pub enum Outcome {
|
||||
/// Execution completed successfully; given weight was used.
|
||||
Complete(Weight),
|
||||
/// Execution started, but did not complete successfully due to the given error; given weight was used.
|
||||
Incomplete(Weight, Error),
|
||||
/// Execution did not start due to the given error.
|
||||
Error(Error),
|
||||
}
|
||||
|
||||
impl Outcome {
|
||||
pub fn ensure_complete(self) -> Result {
|
||||
match self {
|
||||
Outcome::Complete(_) => Ok(()),
|
||||
Outcome::Incomplete(_, e) => Err(e),
|
||||
Outcome::Error(e) => Err(e),
|
||||
}
|
||||
}
|
||||
pub fn ensure_execution(self) -> result::Result<Weight, Error> {
|
||||
match self {
|
||||
Outcome::Complete(w) => Ok(w),
|
||||
Outcome::Incomplete(w, _) => Ok(w),
|
||||
Outcome::Error(e) => Err(e),
|
||||
}
|
||||
}
|
||||
/// How much weight was used by the XCM execution attempt.
|
||||
pub fn weight_used(&self) -> Weight {
|
||||
match self {
|
||||
Outcome::Complete(w) => *w,
|
||||
Outcome::Incomplete(w, _) => *w,
|
||||
Outcome::Error(_) => 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Type of XCM message executor.
|
||||
pub trait ExecuteXcm<RuntimeCall> {
|
||||
/// Execute some XCM `message` from `origin` using no more than `weight_limit` weight. The weight limit is
|
||||
/// a basic hard-limit and the implementation may place further restrictions or requirements on weight and
|
||||
/// other aspects.
|
||||
fn execute_xcm(
|
||||
origin: impl Into<MultiLocation>,
|
||||
message: Xcm<RuntimeCall>,
|
||||
weight_limit: Weight,
|
||||
) -> Outcome {
|
||||
let origin = origin.into();
|
||||
log::debug!(
|
||||
target: "xcm::execute_xcm",
|
||||
"origin: {:?}, message: {:?}, weight_limit: {:?}",
|
||||
origin,
|
||||
message,
|
||||
weight_limit,
|
||||
);
|
||||
Self::execute_xcm_in_credit(origin, message, weight_limit, 0)
|
||||
}
|
||||
|
||||
/// Execute some XCM `message` from `origin` using no more than `weight_limit` weight.
|
||||
///
|
||||
/// Some amount of `weight_credit` may be provided which, depending on the implementation, may allow
|
||||
/// execution without associated payment.
|
||||
fn execute_xcm_in_credit(
|
||||
origin: impl Into<MultiLocation>,
|
||||
message: Xcm<RuntimeCall>,
|
||||
weight_limit: Weight,
|
||||
weight_credit: Weight,
|
||||
) -> Outcome;
|
||||
}
|
||||
|
||||
impl<C> ExecuteXcm<C> for () {
|
||||
fn execute_xcm_in_credit(
|
||||
_origin: impl Into<MultiLocation>,
|
||||
_message: Xcm<C>,
|
||||
_weight_limit: Weight,
|
||||
_weight_credit: Weight,
|
||||
) -> Outcome {
|
||||
Outcome::Error(Error::Unimplemented)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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`
|
||||
/// might alter the destination and the XCM message for to the next router.
|
||||
///
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use xcm::v1::{MultiLocation, Xcm, Junction, Junctions, Error, OriginKind, SendXcm, Result, Parent};
|
||||
/// # use parity_scale_codec::Encode;
|
||||
///
|
||||
/// /// A sender that only passes the message through and does nothing.
|
||||
/// struct Sender1;
|
||||
/// impl SendXcm for Sender1 {
|
||||
/// fn send_xcm(destination: impl Into<MultiLocation>, message: Xcm<()>) -> Result {
|
||||
/// return Err(Error::CannotReachDestination(destination.into(), message))
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// /// A sender that accepts a message that has an X2 junction, otherwise stops the routing.
|
||||
/// struct Sender2;
|
||||
/// impl SendXcm for Sender2 {
|
||||
/// fn send_xcm(destination: impl Into<MultiLocation>, message: Xcm<()>) -> Result {
|
||||
/// let destination = destination.into();
|
||||
/// if matches!(destination.interior(), Junctions::X2(j1, j2))
|
||||
/// && destination.parent_count() == 0
|
||||
/// {
|
||||
/// Ok(())
|
||||
/// } else {
|
||||
/// Err(Error::Undefined)
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// /// A sender that accepts a message from an X1 parent junction, passing through otherwise.
|
||||
/// struct Sender3;
|
||||
/// impl SendXcm for Sender3 {
|
||||
/// fn send_xcm(destination: impl Into<MultiLocation>, message: Xcm<()>) -> Result {
|
||||
/// let destination = destination.into();
|
||||
/// if matches!(destination.interior(), Junctions::Here)
|
||||
/// && destination.parent_count() == 1
|
||||
/// {
|
||||
/// Ok(())
|
||||
/// } else {
|
||||
/// Err(Error::CannotReachDestination(destination, message))
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // A call to send via XCM. We don't really care about this.
|
||||
/// # fn main() {
|
||||
/// let call: Vec<u8> = ().encode();
|
||||
/// let message = Xcm::Transact { origin_type: OriginKind::Superuser, require_weight_at_most: 0, call: call.into() };
|
||||
///
|
||||
/// assert!(
|
||||
/// // Sender2 will block this.
|
||||
/// <(Sender1, Sender2, Sender3) as SendXcm>::send_xcm(Parent, message.clone())
|
||||
/// .is_err()
|
||||
/// );
|
||||
///
|
||||
/// assert!(
|
||||
/// // Sender3 will catch this.
|
||||
/// <(Sender1, Sender3) as SendXcm>::send_xcm(Parent, message.clone())
|
||||
/// .is_ok()
|
||||
/// );
|
||||
/// # }
|
||||
/// ```
|
||||
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
|
||||
/// trying other type fields.
|
||||
fn send_xcm(destination: impl Into<MultiLocation>, message: Xcm<()>) -> Result;
|
||||
}
|
||||
|
||||
#[impl_trait_for_tuples::impl_for_tuples(30)]
|
||||
impl SendXcm for Tuple {
|
||||
fn send_xcm(destination: impl Into<MultiLocation>, message: Xcm<()>) -> Result {
|
||||
for_tuples!( #(
|
||||
// we shadow `destination` and `message` in each expansion for the next one.
|
||||
let (destination, message) = match Tuple::send_xcm(destination, message) {
|
||||
Err(Error::CannotReachDestination(d, m)) => (d, m),
|
||||
o @ _ => return o,
|
||||
};
|
||||
)* );
|
||||
Err(Error::CannotReachDestination(destination.into(), message))
|
||||
}
|
||||
}
|
||||
@@ -17,15 +17,16 @@
|
||||
//! Support data structures for `MultiLocation`, primarily the `Junction` datatype.
|
||||
|
||||
use super::{BodyId, BodyPart, Junctions, MultiLocation, NetworkId};
|
||||
use crate::v0::Junction as Junction0;
|
||||
use crate::v3::Junction as NewJunction;
|
||||
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
use sp_runtime::{traits::ConstU32, WeakBoundedVec};
|
||||
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.
|
||||
///
|
||||
@@ -77,23 +78,30 @@ pub enum Junction {
|
||||
Plurality { id: BodyId, part: BodyPart },
|
||||
}
|
||||
|
||||
impl TryFrom<Junction0> for Junction {
|
||||
impl TryFrom<NewJunction> for Junction {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: Junction0) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
Junction0::Parent => Err(()),
|
||||
Junction0::Parachain(id) => Ok(Self::Parachain(id)),
|
||||
Junction0::AccountId32 { network, id } => Ok(Self::AccountId32 { network, id }),
|
||||
Junction0::AccountIndex64 { network, index } =>
|
||||
Ok(Self::AccountIndex64 { network, index }),
|
||||
Junction0::AccountKey20 { network, key } => Ok(Self::AccountKey20 { network, key }),
|
||||
Junction0::PalletInstance(index) => Ok(Self::PalletInstance(index)),
|
||||
Junction0::GeneralIndex(id) => Ok(Self::GeneralIndex(id)),
|
||||
Junction0::GeneralKey(key) => Ok(Self::GeneralKey(key)),
|
||||
Junction0::OnlyChild => Ok(Self::OnlyChild),
|
||||
Junction0::Plurality { id, part } => Ok(Self::Plurality { id: id.into(), part }),
|
||||
}
|
||||
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(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+392
-208
@@ -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(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,13 +24,20 @@
|
||||
//! 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, result};
|
||||
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,
|
||||
@@ -91,8 +98,24 @@ impl From<Vec<u8>> for AssetInstance {
|
||||
}
|
||||
}
|
||||
|
||||
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>),
|
||||
@@ -110,6 +133,20 @@ impl From<Vec<u8>> for AssetId {
|
||||
}
|
||||
}
|
||||
|
||||
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<(), ()> {
|
||||
@@ -142,6 +179,7 @@ impl AssetId {
|
||||
|
||||
/// 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),
|
||||
@@ -168,7 +206,19 @@ impl<T: Into<AssetInstance>> From<T> for Fungibility {
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -243,47 +293,16 @@ impl MultiAsset {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<super::super::v0::MultiAsset> for MultiAsset {
|
||||
impl TryFrom<NewMultiAsset> for MultiAsset {
|
||||
type Error = ();
|
||||
fn try_from(old: super::super::v0::MultiAsset) -> result::Result<MultiAsset, ()> {
|
||||
use super::super::v0::MultiAsset as V0;
|
||||
use AssetId::*;
|
||||
use Fungibility::*;
|
||||
let (id, fun) = match old {
|
||||
V0::ConcreteFungible { id, amount } => (Concrete(id.try_into()?), Fungible(amount)),
|
||||
V0::ConcreteNonFungible { class, instance } =>
|
||||
(Concrete(class.try_into()?), NonFungible(instance)),
|
||||
V0::AbstractFungible { id, amount } => (Abstract(id), Fungible(amount)),
|
||||
V0::AbstractNonFungible { class, instance } => (Abstract(class), NonFungible(instance)),
|
||||
_ => return Err(()),
|
||||
};
|
||||
Ok(MultiAsset { id, fun })
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<super::super::v0::MultiAsset> for Option<MultiAsset> {
|
||||
type Error = ();
|
||||
fn try_from(old: super::super::v0::MultiAsset) -> result::Result<Option<MultiAsset>, ()> {
|
||||
match old {
|
||||
super::super::v0::MultiAsset::None => return Ok(None),
|
||||
x => return Ok(Some(x.try_into()?)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Vec<super::super::v0::MultiAsset>> for MultiAsset {
|
||||
type Error = ();
|
||||
fn try_from(mut old: Vec<super::super::v0::MultiAsset>) -> result::Result<MultiAsset, ()> {
|
||||
if old.len() == 1 {
|
||||
old.remove(0).try_into()
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
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 {
|
||||
@@ -293,15 +312,15 @@ impl Decode for MultiAssets {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Vec<super::super::v0::MultiAsset>> for MultiAssets {
|
||||
impl TryFrom<NewMultiAssets> for MultiAssets {
|
||||
type Error = ();
|
||||
fn try_from(old: Vec<super::super::v0::MultiAsset>) -> result::Result<MultiAssets, ()> {
|
||||
let v = old
|
||||
fn try_from(new: NewMultiAssets) -> Result<Self, ()> {
|
||||
let v = new
|
||||
.into_inner()
|
||||
.into_iter()
|
||||
.map(Option::<MultiAsset>::try_from)
|
||||
.filter_map(|x| x.transpose())
|
||||
.collect::<result::Result<Vec<MultiAsset>, ()>>()?;
|
||||
Ok(v.into())
|
||||
.map(MultiAsset::try_from)
|
||||
.collect::<Result<Vec<_>, ()>>()?;
|
||||
Ok(MultiAssets(v))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,7 +454,8 @@ impl MultiAssets {
|
||||
self.0.iter_mut().try_for_each(|i| i.prepend_with(prefix))
|
||||
}
|
||||
|
||||
/// Prepend a `MultiLocation` to any concrete asset items, giving it a new root location.
|
||||
/// 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))
|
||||
}
|
||||
@@ -445,15 +465,29 @@ impl MultiAssets {
|
||||
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).
|
||||
@@ -463,35 +497,6 @@ pub enum WildMultiAsset {
|
||||
AllOf { id: AssetId, fun: WildFungibility },
|
||||
}
|
||||
|
||||
impl TryFrom<super::super::v0::MultiAsset> for WildMultiAsset {
|
||||
type Error = ();
|
||||
fn try_from(old: super::super::v0::MultiAsset) -> result::Result<WildMultiAsset, ()> {
|
||||
use super::super::v0::MultiAsset as V0;
|
||||
use AssetId::*;
|
||||
use WildFungibility::*;
|
||||
let (id, fun) = match old {
|
||||
V0::All => return Ok(WildMultiAsset::All),
|
||||
V0::AllConcreteFungible { id } => (Concrete(id.try_into()?), Fungible),
|
||||
V0::AllConcreteNonFungible { class } => (Concrete(class.try_into()?), NonFungible),
|
||||
V0::AllAbstractFungible { id } => (Abstract(id), Fungible),
|
||||
V0::AllAbstractNonFungible { class } => (Abstract(class), NonFungible),
|
||||
_ => return Err(()),
|
||||
};
|
||||
Ok(WildMultiAsset::AllOf { id, fun })
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Vec<super::super::v0::MultiAsset>> for WildMultiAsset {
|
||||
type Error = ();
|
||||
fn try_from(mut old: Vec<super::super::v0::MultiAsset>) -> result::Result<WildMultiAsset, ()> {
|
||||
if old.len() == 1 {
|
||||
old.remove(0).try_into()
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WildMultiAsset {
|
||||
/// Returns true if `self` is a super-set of the given `inner`.
|
||||
///
|
||||
@@ -505,7 +510,8 @@ impl WildMultiAsset {
|
||||
}
|
||||
}
|
||||
|
||||
/// Prepend a `MultiLocation` to any concrete asset components, giving it a new root location.
|
||||
/// 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 {
|
||||
@@ -526,6 +532,7 @@ impl<A: Into<AssetId>, B: Into<WildFungibility>> From<(A, B)> for WildMultiAsset
|
||||
/// 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),
|
||||
@@ -567,7 +574,8 @@ impl MultiAssetFilter {
|
||||
}
|
||||
}
|
||||
|
||||
/// Prepend a `MultiLocation` to any concrete asset components, giving it a new root location.
|
||||
/// 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),
|
||||
@@ -576,15 +584,25 @@ impl MultiAssetFilter {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Vec<super::super::v0::MultiAsset>> for MultiAssetFilter {
|
||||
impl TryFrom<NewWildMultiAsset> for WildMultiAsset {
|
||||
type Error = ();
|
||||
fn try_from(
|
||||
mut old: Vec<super::super::v0::MultiAsset>,
|
||||
) -> result::Result<MultiAssetFilter, ()> {
|
||||
if old.len() == 1 && old[0].is_wildcard() {
|
||||
Ok(MultiAssetFilter::Wild(old.remove(0).try_into()?))
|
||||
} else {
|
||||
Ok(MultiAssetFilter::Definite(old.try_into()?))
|
||||
}
|
||||
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()?),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
//! Cross-Consensus Message format data structures.
|
||||
|
||||
use super::Junction;
|
||||
use crate::v3::MultiLocation as NewMultiLocation;
|
||||
use core::{mem, result};
|
||||
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
@@ -48,6 +49,7 @@ use scale_info::TypeInfo;
|
||||
///
|
||||
/// The `MultiLocation` value of `Null` simply refers to the interpreting consensus system.
|
||||
#[derive(Clone, Decode, Encode, Eq, PartialEq, Ord, PartialOrd, Debug, TypeInfo, MaxEncodedLen)]
|
||||
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct MultiLocation {
|
||||
/// The number of parent junctions at the beginning of this `MultiLocation`.
|
||||
pub parents: u8,
|
||||
@@ -236,7 +238,7 @@ impl MultiLocation {
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use xcm::v1::{Junctions::*, Junction::*, MultiLocation};
|
||||
/// # use xcm::v2::{Junctions::*, Junction::*, MultiLocation};
|
||||
/// # fn main() {
|
||||
/// let mut m = MultiLocation::new(1, X2(PalletInstance(3), OnlyChild));
|
||||
/// assert_eq!(
|
||||
@@ -258,7 +260,7 @@ impl MultiLocation {
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use xcm::v1::{Junctions::*, Junction::*, MultiLocation};
|
||||
/// # use xcm::v2::{Junctions::*, Junction::*, MultiLocation};
|
||||
/// let m = MultiLocation::new(1, X3(PalletInstance(3), OnlyChild, OnlyChild));
|
||||
/// assert!(m.starts_with(&MultiLocation::new(1, X1(PalletInstance(3)))));
|
||||
/// assert!(!m.starts_with(&MultiLocation::new(1, X1(GeneralIndex(99)))));
|
||||
@@ -277,7 +279,7 @@ impl MultiLocation {
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use xcm::v1::{Junctions::*, Junction::*, MultiLocation};
|
||||
/// # use xcm::v2::{Junctions::*, Junction::*, MultiLocation};
|
||||
/// # fn main() {
|
||||
/// let mut m = MultiLocation::new(1, X1(Parachain(21)));
|
||||
/// assert_eq!(m.append_with(X1(PalletInstance(3))), Ok(()));
|
||||
@@ -300,7 +302,7 @@ impl MultiLocation {
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use xcm::v1::{Junctions::*, Junction::*, MultiLocation};
|
||||
/// # use xcm::v2::{Junctions::*, Junction::*, MultiLocation};
|
||||
/// # fn main() {
|
||||
/// let mut m = MultiLocation::new(2, X1(PalletInstance(3)));
|
||||
/// assert_eq!(m.prepend_with(MultiLocation::new(1, X2(Parachain(21), OnlyChild))), Ok(()));
|
||||
@@ -342,6 +344,21 @@ impl MultiLocation {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Consume `self` and return the value representing the same location from the point of view
|
||||
/// of `target`. The context of `self` is provided as `ancestry`.
|
||||
///
|
||||
/// Returns an `Err` with the unmodified `self` in the case of error.
|
||||
pub fn reanchored(
|
||||
mut self,
|
||||
target: &MultiLocation,
|
||||
ancestry: &MultiLocation,
|
||||
) -> Result<Self, Self> {
|
||||
match self.reanchor(target, ancestry) {
|
||||
Ok(()) => Ok(self),
|
||||
Err(()) => Err(self),
|
||||
}
|
||||
}
|
||||
|
||||
/// Mutate `self` so that it represents the same location from the point of view of `target`.
|
||||
/// The context of `self` is provided as `ancestry`.
|
||||
///
|
||||
@@ -397,6 +414,13 @@ impl MultiLocation {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<NewMultiLocation> for MultiLocation {
|
||||
type Error = ();
|
||||
fn try_from(x: NewMultiLocation) -> result::Result<Self, ()> {
|
||||
Ok(MultiLocation { parents: x.parents, interior: x.interior.try_into()? })
|
||||
}
|
||||
}
|
||||
|
||||
/// A unit struct which can be converted into a `MultiLocation` of `parents` value 1.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||
pub struct Parent;
|
||||
@@ -408,7 +432,7 @@ impl From<Parent> for MultiLocation {
|
||||
|
||||
/// A tuple struct which can be converted into a `MultiLocation` of `parents` value 1 with the inner interior.
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||
pub struct ParentThen(Junctions);
|
||||
pub struct ParentThen(pub Junctions);
|
||||
impl From<ParentThen> for MultiLocation {
|
||||
fn from(ParentThen(interior): ParentThen) -> Self {
|
||||
MultiLocation { parents: 1, interior }
|
||||
@@ -417,7 +441,7 @@ impl From<ParentThen> for MultiLocation {
|
||||
|
||||
/// A unit struct which can be converted into a `MultiLocation` of the inner `parents` value.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||
pub struct Ancestor(u8);
|
||||
pub struct Ancestor(pub u8);
|
||||
impl From<Ancestor> for MultiLocation {
|
||||
fn from(Ancestor(parents): Ancestor) -> Self {
|
||||
MultiLocation { parents, interior: Junctions::Here }
|
||||
@@ -426,14 +450,14 @@ impl From<Ancestor> for MultiLocation {
|
||||
|
||||
/// A unit struct which can be converted into a `MultiLocation` of the inner `parents` value and the inner interior.
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||
pub struct AncestorThen(u8, Junctions);
|
||||
impl From<AncestorThen> for MultiLocation {
|
||||
fn from(AncestorThen(parents, interior): AncestorThen) -> Self {
|
||||
MultiLocation { parents, interior }
|
||||
pub struct AncestorThen<Interior>(pub u8, pub Interior);
|
||||
impl<Interior: Into<Junctions>> From<AncestorThen<Interior>> for MultiLocation {
|
||||
fn from(AncestorThen(parents, interior): AncestorThen<Interior>) -> Self {
|
||||
MultiLocation { parents, interior: interior.into() }
|
||||
}
|
||||
}
|
||||
|
||||
xcm_procedural::impl_conversion_functions_for_multilocation_v1!();
|
||||
xcm_procedural::impl_conversion_functions_for_multilocation_v2!();
|
||||
|
||||
/// Maximum number of `Junction`s that a `Junctions` can contain.
|
||||
const MAX_JUNCTIONS: usize = 8;
|
||||
@@ -444,6 +468,7 @@ const MAX_JUNCTIONS: usize = 8;
|
||||
/// Parent junctions cannot be constructed with this type. Refer to `MultiLocation` for
|
||||
/// instructions on constructing parent junctions.
|
||||
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
|
||||
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum Junctions {
|
||||
/// The interpreting consensus system.
|
||||
Here,
|
||||
@@ -811,7 +836,7 @@ impl Junctions {
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use xcm::v1::{Junctions::*, Junction::*};
|
||||
/// # use xcm::v2::{Junctions::*, Junction::*};
|
||||
/// # fn main() {
|
||||
/// let mut m = X3(Parachain(2), PalletInstance(3), OnlyChild);
|
||||
/// assert_eq!(m.match_and_split(&X2(Parachain(2), PalletInstance(3))), Some(&OnlyChild));
|
||||
@@ -829,7 +854,7 @@ impl Junctions {
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use xcm::v1::{Junctions::*, Junction::*};
|
||||
/// # use xcm::v2::{Junctions::*, Junction::*};
|
||||
/// let mut j = X3(Parachain(2), PalletInstance(3), OnlyChild);
|
||||
/// assert!(j.starts_with(&X2(Parachain(2), PalletInstance(3))));
|
||||
/// assert!(j.starts_with(&j));
|
||||
@@ -859,7 +884,7 @@ impl TryFrom<MultiLocation> for Junctions {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{Ancestor, AncestorThen, Junctions::*, MultiLocation, Parent, ParentThen};
|
||||
use crate::opaque::v1::{Junction::*, NetworkId::*};
|
||||
use crate::opaque::v2::{Junction::*, NetworkId::*};
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
|
||||
#[test]
|
||||
@@ -1062,7 +1087,6 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn conversion_from_other_types_works() {
|
||||
use crate::v0;
|
||||
fn takes_multilocation<Arg: Into<MultiLocation>>(_arg: Arg) {}
|
||||
|
||||
takes_multilocation(Parent);
|
||||
@@ -1079,27 +1103,5 @@ mod tests {
|
||||
takes_multilocation((Parent, Here));
|
||||
takes_multilocation(ParentThen(X1(Parachain(75))));
|
||||
takes_multilocation([Parachain(100), PalletInstance(3)]);
|
||||
|
||||
assert_eq!(v0::MultiLocation::Null.try_into(), Ok(MultiLocation::here()));
|
||||
assert_eq!(
|
||||
v0::MultiLocation::X1(v0::Junction::Parent).try_into(),
|
||||
Ok(MultiLocation::parent())
|
||||
);
|
||||
assert_eq!(
|
||||
v0::MultiLocation::X2(v0::Junction::Parachain(88), v0::Junction::Parent).try_into(),
|
||||
Ok(MultiLocation::here()),
|
||||
);
|
||||
assert_eq!(
|
||||
v0::MultiLocation::X3(
|
||||
v0::Junction::Parent,
|
||||
v0::Junction::Parent,
|
||||
v0::Junction::GeneralKey(b"foo".to_vec().try_into().unwrap()),
|
||||
)
|
||||
.try_into(),
|
||||
Ok(MultiLocation {
|
||||
parents: 2,
|
||||
interior: X1(GeneralKey(b"foo".to_vec().try_into().unwrap()))
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,342 @@
|
||||
// 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::{Junctions, MultiLocation};
|
||||
use crate::{
|
||||
v2::{
|
||||
BodyId as OldBodyId, BodyPart as OldBodyPart, Junction as OldJunction,
|
||||
NetworkId as OldNetworkId,
|
||||
},
|
||||
VersionedMultiLocation,
|
||||
};
|
||||
use core::convert::{TryFrom, TryInto};
|
||||
use parity_scale_codec::{self, Decode, Encode, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
/// A global identifier of a data structure existing within consensus.
|
||||
///
|
||||
/// Maintenance note: Networks with global consensus and which are practically bridgeable within the
|
||||
/// Polkadot ecosystem are given preference over explicit naming in this enumeration.
|
||||
#[derive(
|
||||
Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen,
|
||||
)]
|
||||
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum NetworkId {
|
||||
/// Network specified by the first 32 bytes of its genesis block.
|
||||
ByGenesis([u8; 32]),
|
||||
/// Network defined by the first 32-bytes of the hash and number of some block it contains.
|
||||
ByFork { block_number: u64, block_hash: [u8; 32] },
|
||||
/// The Polkadot mainnet Relay-chain.
|
||||
Polkadot,
|
||||
/// The Kusama canary-net Relay-chain.
|
||||
Kusama,
|
||||
/// The Westend testnet Relay-chain.
|
||||
Westend,
|
||||
/// The Rococo testnet Relay-chain.
|
||||
Rococo,
|
||||
/// The Wococo testnet Relay-chain.
|
||||
Wococo,
|
||||
/// An Ethereum network specified by its chain ID.
|
||||
Ethereum {
|
||||
/// The EIP-155 chain ID.
|
||||
#[codec(compact)]
|
||||
chain_id: u64,
|
||||
},
|
||||
/// The Bitcoin network, including hard-forks supported by Bitcoin Core development team.
|
||||
BitcoinCore,
|
||||
/// The Bitcoin network, including hard-forks supported by Bitcoin Cash developers.
|
||||
BitcoinCash,
|
||||
}
|
||||
|
||||
impl From<OldNetworkId> for Option<NetworkId> {
|
||||
fn from(old: OldNetworkId) -> Option<NetworkId> {
|
||||
use OldNetworkId::*;
|
||||
match old {
|
||||
Any => None,
|
||||
Named(_) => None,
|
||||
Polkadot => Some(NetworkId::Polkadot),
|
||||
Kusama => Some(NetworkId::Kusama),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An identifier of a pluralistic body.
|
||||
#[derive(
|
||||
Copy, 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.
|
||||
Moniker([u8; 4]),
|
||||
/// 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 TryFrom<OldBodyId> for BodyId {
|
||||
type Error = ();
|
||||
fn try_from(value: OldBodyId) -> Result<Self, ()> {
|
||||
use OldBodyId::*;
|
||||
Ok(match value {
|
||||
Unit => Self::Unit,
|
||||
Named(n) =>
|
||||
if n.len() == 4 {
|
||||
let mut r = [0u8; 4];
|
||||
r.copy_from_slice(&n[..]);
|
||||
Self::Moniker(r)
|
||||
} else {
|
||||
return Err(())
|
||||
},
|
||||
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(
|
||||
Copy, 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 TryFrom<OldBodyPart> for BodyPart {
|
||||
type Error = ();
|
||||
fn try_from(value: OldBodyPart) -> Result<Self, ()> {
|
||||
use OldBodyPart::*;
|
||||
Ok(match value {
|
||||
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 },
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// 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(
|
||||
Copy, 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: Option<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: Option<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: Option<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 128-byte 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([u8; 32]),
|
||||
/// The unambiguous child.
|
||||
///
|
||||
/// Not currently used except as a fallback when deriving context.
|
||||
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 },
|
||||
/// A global network capable of externalizing its own consensus. This is not generally
|
||||
/// meaningful outside of the universal level.
|
||||
GlobalConsensus(NetworkId),
|
||||
}
|
||||
|
||||
impl From<NetworkId> for Junction {
|
||||
fn from(n: NetworkId) -> Self {
|
||||
Self::GlobalConsensus(n)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[u8; 32]> for Junction {
|
||||
fn from(id: [u8; 32]) -> Self {
|
||||
Self::AccountId32 { network: None, id }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[u8; 20]> for Junction {
|
||||
fn from(key: [u8; 20]) -> Self {
|
||||
Self::AccountKey20 { network: None, key }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for Junction {
|
||||
fn from(index: u64) -> Self {
|
||||
Self::AccountIndex64 { network: None, index }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u128> for Junction {
|
||||
fn from(id: u128) -> Self {
|
||||
Self::GeneralIndex(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<OldJunction> for Junction {
|
||||
type Error = ();
|
||||
fn try_from(value: OldJunction) -> Result<Self, ()> {
|
||||
use OldJunction::*;
|
||||
Ok(match value {
|
||||
Parachain(id) => Self::Parachain(id),
|
||||
AccountId32 { network, id } => Self::AccountId32 { network: network.into(), id },
|
||||
AccountIndex64 { network, index } =>
|
||||
Self::AccountIndex64 { network: network.into(), index },
|
||||
AccountKey20 { network, key } => Self::AccountKey20 { network: network.into(), key },
|
||||
PalletInstance(index) => Self::PalletInstance(index),
|
||||
GeneralIndex(id) => Self::GeneralIndex(id),
|
||||
GeneralKey(_key) => return Err(()),
|
||||
OnlyChild => Self::OnlyChild,
|
||||
Plurality { id, part } =>
|
||||
Self::Plurality { id: id.try_into()?, part: part.try_into()? },
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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_location(self) -> MultiLocation {
|
||||
MultiLocation { parents: 0, interior: Junctions::X1(self) }
|
||||
}
|
||||
|
||||
/// Convert `self` into a `MultiLocation` containing `n` parents.
|
||||
///
|
||||
/// Similar to `Self::into_location`, 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) }
|
||||
}
|
||||
|
||||
/// Convert `self` into a `VersionedMultiLocation` containing 0 parents.
|
||||
///
|
||||
/// Similar to `Into::into`, except that this method can be used in a const evaluation context.
|
||||
pub const fn into_versioned(self) -> VersionedMultiLocation {
|
||||
self.into_location().into_versioned()
|
||||
}
|
||||
|
||||
/// Remove the `NetworkId` value.
|
||||
pub fn remove_network_id(&mut self) {
|
||||
use Junction::*;
|
||||
match self {
|
||||
AccountId32 { ref mut network, .. } |
|
||||
AccountIndex64 { ref mut network, .. } |
|
||||
AccountKey20 { ref mut network, .. } => *network = None,
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,708 @@
|
||||
// Copyright 2020-2021 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/>.
|
||||
|
||||
//! XCM `Junctions`/`InteriorMultiLocation` datatype.
|
||||
|
||||
use super::{Junction, MultiLocation, NetworkId};
|
||||
use core::{convert::TryFrom, mem, result};
|
||||
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
/// Maximum number of `Junction`s that a `Junctions` can contain.
|
||||
pub(crate) const MAX_JUNCTIONS: usize = 8;
|
||||
|
||||
/// Non-parent junctions that can be constructed, up to the length of 8. This specific `Junctions`
|
||||
/// implementation uses a Rust `enum` in order to make pattern matching easier.
|
||||
///
|
||||
/// Parent junctions cannot be constructed with this type. Refer to `MultiLocation` for
|
||||
/// instructions on constructing parent junctions.
|
||||
#[derive(
|
||||
Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen,
|
||||
)]
|
||||
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum Junctions {
|
||||
/// The interpreting consensus system.
|
||||
Here,
|
||||
/// A relative path comprising 1 junction.
|
||||
X1(Junction),
|
||||
/// A relative path comprising 2 junctions.
|
||||
X2(Junction, Junction),
|
||||
/// A relative path comprising 3 junctions.
|
||||
X3(Junction, Junction, Junction),
|
||||
/// A relative path comprising 4 junctions.
|
||||
X4(Junction, Junction, Junction, Junction),
|
||||
/// A relative path comprising 5 junctions.
|
||||
X5(Junction, Junction, Junction, Junction, Junction),
|
||||
/// A relative path comprising 6 junctions.
|
||||
X6(Junction, Junction, Junction, Junction, Junction, Junction),
|
||||
/// A relative path comprising 7 junctions.
|
||||
X7(Junction, Junction, Junction, Junction, Junction, Junction, Junction),
|
||||
/// A relative path comprising 8 junctions.
|
||||
X8(Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction),
|
||||
}
|
||||
|
||||
pub struct JunctionsIterator(Junctions);
|
||||
impl Iterator for JunctionsIterator {
|
||||
type Item = Junction;
|
||||
fn next(&mut self) -> Option<Junction> {
|
||||
self.0.take_first()
|
||||
}
|
||||
}
|
||||
|
||||
impl DoubleEndedIterator for JunctionsIterator {
|
||||
fn next_back(&mut self) -> Option<Junction> {
|
||||
self.0.take_last()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct JunctionsRefIterator<'a> {
|
||||
junctions: &'a Junctions,
|
||||
next: usize,
|
||||
back: usize,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for JunctionsRefIterator<'a> {
|
||||
type Item = &'a Junction;
|
||||
fn next(&mut self) -> Option<&'a Junction> {
|
||||
if self.next.saturating_add(self.back) >= self.junctions.len() {
|
||||
return None
|
||||
}
|
||||
|
||||
let result = self.junctions.at(self.next);
|
||||
self.next += 1;
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DoubleEndedIterator for JunctionsRefIterator<'a> {
|
||||
fn next_back(&mut self) -> Option<&'a Junction> {
|
||||
let next_back = self.back.saturating_add(1);
|
||||
// checked_sub here, because if the result is less than 0, we end iteration
|
||||
let index = self.junctions.len().checked_sub(next_back)?;
|
||||
if self.next > index {
|
||||
return None
|
||||
}
|
||||
self.back = next_back;
|
||||
|
||||
self.junctions.at(index)
|
||||
}
|
||||
}
|
||||
impl<'a> IntoIterator for &'a Junctions {
|
||||
type Item = &'a Junction;
|
||||
type IntoIter = JunctionsRefIterator<'a>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
JunctionsRefIterator { junctions: self, next: 0, back: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for Junctions {
|
||||
type Item = Junction;
|
||||
type IntoIter = JunctionsIterator;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
JunctionsIterator(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Junctions {
|
||||
/// 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_location(self) -> MultiLocation {
|
||||
MultiLocation { parents: 0, interior: self }
|
||||
}
|
||||
|
||||
/// Convert `self` into a `MultiLocation` containing `n` parents.
|
||||
///
|
||||
/// Similar to `Self::into_location`, with the added ability to specify the number of parent junctions.
|
||||
pub const fn into_exterior(self, n: u8) -> MultiLocation {
|
||||
MultiLocation { parents: n, interior: self }
|
||||
}
|
||||
|
||||
/// Remove the `NetworkId` value in any `Junction`s.
|
||||
pub fn remove_network_id(&mut self) {
|
||||
self.for_each_mut(Junction::remove_network_id);
|
||||
}
|
||||
|
||||
/// Treating `self` as the universal context, return the location of the local consensus system
|
||||
/// from the point of view of the given `target`.
|
||||
pub fn invert_target(mut self, target: &MultiLocation) -> Result<MultiLocation, ()> {
|
||||
let mut junctions = Self::Here;
|
||||
for _ in 0..target.parent_count() {
|
||||
junctions = junctions
|
||||
.pushed_front_with(self.take_last().unwrap_or(Junction::OnlyChild))
|
||||
.map_err(|_| ())?;
|
||||
}
|
||||
let parents = target.interior().len() as u8;
|
||||
Ok(MultiLocation::new(parents, junctions))
|
||||
}
|
||||
|
||||
/// Execute a function `f` on every junction. We use this since we cannot implement a mutable
|
||||
/// `Iterator` without unsafe code.
|
||||
pub fn for_each_mut(&mut self, mut x: impl FnMut(&mut Junction)) {
|
||||
match self {
|
||||
Junctions::Here => {},
|
||||
Junctions::X1(a) => {
|
||||
x(a);
|
||||
},
|
||||
Junctions::X2(a, b) => {
|
||||
x(a);
|
||||
x(b);
|
||||
},
|
||||
Junctions::X3(a, b, c) => {
|
||||
x(a);
|
||||
x(b);
|
||||
x(c);
|
||||
},
|
||||
Junctions::X4(a, b, c, d) => {
|
||||
x(a);
|
||||
x(b);
|
||||
x(c);
|
||||
x(d);
|
||||
},
|
||||
Junctions::X5(a, b, c, d, e) => {
|
||||
x(a);
|
||||
x(b);
|
||||
x(c);
|
||||
x(d);
|
||||
x(e);
|
||||
},
|
||||
Junctions::X6(a, b, c, d, e, f) => {
|
||||
x(a);
|
||||
x(b);
|
||||
x(c);
|
||||
x(d);
|
||||
x(e);
|
||||
x(f);
|
||||
},
|
||||
Junctions::X7(a, b, c, d, e, f, g) => {
|
||||
x(a);
|
||||
x(b);
|
||||
x(c);
|
||||
x(d);
|
||||
x(e);
|
||||
x(f);
|
||||
x(g);
|
||||
},
|
||||
Junctions::X8(a, b, c, d, e, f, g, h) => {
|
||||
x(a);
|
||||
x(b);
|
||||
x(c);
|
||||
x(d);
|
||||
x(e);
|
||||
x(f);
|
||||
x(g);
|
||||
x(h);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract the network ID treating this value as a universal location.
|
||||
///
|
||||
/// This will return an `Err` if the first item is not a `GlobalConsensus`, which would indicate
|
||||
/// that this value is not a universal location.
|
||||
pub fn global_consensus(&self) -> Result<NetworkId, ()> {
|
||||
if let Some(Junction::GlobalConsensus(network)) = self.first() {
|
||||
Ok(*network)
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract the network ID and the interior consensus location, treating this value as a
|
||||
/// universal location.
|
||||
///
|
||||
/// This will return an `Err` if the first item is not a `GlobalConsensus`, which would indicate
|
||||
/// that this value is not a universal location.
|
||||
pub fn split_global(self) -> Result<(NetworkId, Junctions), ()> {
|
||||
match self.split_first() {
|
||||
(location, Some(Junction::GlobalConsensus(network))) => Ok((network, location)),
|
||||
_ => return Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Treat `self` as a universal location and the context of `relative`, returning the universal
|
||||
/// location of relative.
|
||||
///
|
||||
/// This will return an error if `relative` has as many (or more) parents than there are
|
||||
/// junctions in `self`, implying that relative refers into a different global consensus.
|
||||
pub fn within_global(mut self, relative: MultiLocation) -> Result<Self, ()> {
|
||||
if self.len() <= relative.parents as usize {
|
||||
return Err(())
|
||||
}
|
||||
for _ in 0..relative.parents {
|
||||
self.take_last();
|
||||
}
|
||||
for j in relative.interior {
|
||||
self.push(j).map_err(|_| ())?;
|
||||
}
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Consumes `self` and returns how `viewer` would address it locally.
|
||||
pub fn relative_to(mut self, viewer: &Junctions) -> MultiLocation {
|
||||
let mut i = 0;
|
||||
while match (self.first(), viewer.at(i)) {
|
||||
(Some(x), Some(y)) => x == y,
|
||||
_ => false,
|
||||
} {
|
||||
self = self.split_first().0;
|
||||
// NOTE: Cannot overflow as loop can only iterate at most `MAX_JUNCTIONS` times.
|
||||
i += 1;
|
||||
}
|
||||
// AUDIT NOTES:
|
||||
// - above loop ensures that `i <= viewer.len()`.
|
||||
// - `viewer.len()` is at most `MAX_JUNCTIONS`, so won't overflow a `u8`.
|
||||
MultiLocation { parents: (viewer.len() - i) as u8, interior: self }
|
||||
}
|
||||
|
||||
/// Returns first junction, or `None` if the location is empty.
|
||||
pub fn first(&self) -> Option<&Junction> {
|
||||
match &self {
|
||||
Junctions::Here => None,
|
||||
Junctions::X1(ref a) => Some(a),
|
||||
Junctions::X2(ref a, ..) => Some(a),
|
||||
Junctions::X3(ref a, ..) => Some(a),
|
||||
Junctions::X4(ref a, ..) => Some(a),
|
||||
Junctions::X5(ref a, ..) => Some(a),
|
||||
Junctions::X6(ref a, ..) => Some(a),
|
||||
Junctions::X7(ref a, ..) => Some(a),
|
||||
Junctions::X8(ref a, ..) => Some(a),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns last junction, or `None` if the location is empty.
|
||||
pub fn last(&self) -> Option<&Junction> {
|
||||
match &self {
|
||||
Junctions::Here => None,
|
||||
Junctions::X1(ref a) => Some(a),
|
||||
Junctions::X2(.., ref a) => Some(a),
|
||||
Junctions::X3(.., ref a) => Some(a),
|
||||
Junctions::X4(.., ref a) => Some(a),
|
||||
Junctions::X5(.., ref a) => Some(a),
|
||||
Junctions::X6(.., ref a) => Some(a),
|
||||
Junctions::X7(.., ref a) => Some(a),
|
||||
Junctions::X8(.., ref a) => Some(a),
|
||||
}
|
||||
}
|
||||
|
||||
/// Splits off the first junction, returning the remaining suffix (first item in tuple) and the first element
|
||||
/// (second item in tuple) or `None` if it was empty.
|
||||
pub fn split_first(self) -> (Junctions, Option<Junction>) {
|
||||
match self {
|
||||
Junctions::Here => (Junctions::Here, None),
|
||||
Junctions::X1(a) => (Junctions::Here, Some(a)),
|
||||
Junctions::X2(a, b) => (Junctions::X1(b), Some(a)),
|
||||
Junctions::X3(a, b, c) => (Junctions::X2(b, c), Some(a)),
|
||||
Junctions::X4(a, b, c, d) => (Junctions::X3(b, c, d), Some(a)),
|
||||
Junctions::X5(a, b, c, d, e) => (Junctions::X4(b, c, d, e), Some(a)),
|
||||
Junctions::X6(a, b, c, d, e, f) => (Junctions::X5(b, c, d, e, f), Some(a)),
|
||||
Junctions::X7(a, b, c, d, e, f, g) => (Junctions::X6(b, c, d, e, f, g), Some(a)),
|
||||
Junctions::X8(a, b, c, d, e, f, g, h) => (Junctions::X7(b, c, d, e, f, g, h), Some(a)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Splits off the last junction, returning the remaining prefix (first item in tuple) and the last element
|
||||
/// (second item in tuple) or `None` if it was empty.
|
||||
pub fn split_last(self) -> (Junctions, Option<Junction>) {
|
||||
match self {
|
||||
Junctions::Here => (Junctions::Here, None),
|
||||
Junctions::X1(a) => (Junctions::Here, Some(a)),
|
||||
Junctions::X2(a, b) => (Junctions::X1(a), Some(b)),
|
||||
Junctions::X3(a, b, c) => (Junctions::X2(a, b), Some(c)),
|
||||
Junctions::X4(a, b, c, d) => (Junctions::X3(a, b, c), Some(d)),
|
||||
Junctions::X5(a, b, c, d, e) => (Junctions::X4(a, b, c, d), Some(e)),
|
||||
Junctions::X6(a, b, c, d, e, f) => (Junctions::X5(a, b, c, d, e), Some(f)),
|
||||
Junctions::X7(a, b, c, d, e, f, g) => (Junctions::X6(a, b, c, d, e, f), Some(g)),
|
||||
Junctions::X8(a, b, c, d, e, f, g, h) => (Junctions::X7(a, b, c, d, e, f, g), Some(h)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes the first element from `self`, returning it (or `None` if it was empty).
|
||||
pub fn take_first(&mut self) -> Option<Junction> {
|
||||
let mut d = Junctions::Here;
|
||||
mem::swap(&mut *self, &mut d);
|
||||
let (tail, head) = d.split_first();
|
||||
*self = tail;
|
||||
head
|
||||
}
|
||||
|
||||
/// Removes the last element from `self`, returning it (or `None` if it was empty).
|
||||
pub fn take_last(&mut self) -> Option<Junction> {
|
||||
let mut d = Junctions::Here;
|
||||
mem::swap(&mut *self, &mut d);
|
||||
let (head, tail) = d.split_last();
|
||||
*self = head;
|
||||
tail
|
||||
}
|
||||
|
||||
/// Mutates `self` to be appended with `new` or returns an `Err` with `new` if would overflow.
|
||||
pub fn push(&mut self, new: impl Into<Junction>) -> result::Result<(), Junction> {
|
||||
let new = new.into();
|
||||
let mut dummy = Junctions::Here;
|
||||
mem::swap(self, &mut dummy);
|
||||
match dummy.pushed_with(new) {
|
||||
Ok(s) => {
|
||||
*self = s;
|
||||
Ok(())
|
||||
},
|
||||
Err((s, j)) => {
|
||||
*self = s;
|
||||
Err(j)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Mutates `self` to be prepended with `new` or returns an `Err` with `new` if would overflow.
|
||||
pub fn push_front(&mut self, new: impl Into<Junction>) -> result::Result<(), Junction> {
|
||||
let new = new.into();
|
||||
let mut dummy = Junctions::Here;
|
||||
mem::swap(self, &mut dummy);
|
||||
match dummy.pushed_front_with(new) {
|
||||
Ok(s) => {
|
||||
*self = s;
|
||||
Ok(())
|
||||
},
|
||||
Err((s, j)) => {
|
||||
*self = s;
|
||||
Err(j)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Consumes `self` and returns a `Junctions` suffixed with `new`, or an `Err` with the
|
||||
/// original value of `self` and `new` in case of overflow.
|
||||
pub fn pushed_with(self, new: impl Into<Junction>) -> result::Result<Self, (Self, Junction)> {
|
||||
let new = new.into();
|
||||
Ok(match self {
|
||||
Junctions::Here => Junctions::X1(new),
|
||||
Junctions::X1(a) => Junctions::X2(a, new),
|
||||
Junctions::X2(a, b) => Junctions::X3(a, b, new),
|
||||
Junctions::X3(a, b, c) => Junctions::X4(a, b, c, new),
|
||||
Junctions::X4(a, b, c, d) => Junctions::X5(a, b, c, d, new),
|
||||
Junctions::X5(a, b, c, d, e) => Junctions::X6(a, b, c, d, e, new),
|
||||
Junctions::X6(a, b, c, d, e, f) => Junctions::X7(a, b, c, d, e, f, new),
|
||||
Junctions::X7(a, b, c, d, e, f, g) => Junctions::X8(a, b, c, d, e, f, g, new),
|
||||
s => Err((s, new))?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Consumes `self` and returns a `Junctions` prefixed with `new`, or an `Err` with the
|
||||
/// original value of `self` and `new` in case of overflow.
|
||||
pub fn pushed_front_with(
|
||||
self,
|
||||
new: impl Into<Junction>,
|
||||
) -> result::Result<Self, (Self, Junction)> {
|
||||
let new = new.into();
|
||||
Ok(match self {
|
||||
Junctions::Here => Junctions::X1(new),
|
||||
Junctions::X1(a) => Junctions::X2(new, a),
|
||||
Junctions::X2(a, b) => Junctions::X3(new, a, b),
|
||||
Junctions::X3(a, b, c) => Junctions::X4(new, a, b, c),
|
||||
Junctions::X4(a, b, c, d) => Junctions::X5(new, a, b, c, d),
|
||||
Junctions::X5(a, b, c, d, e) => Junctions::X6(new, a, b, c, d, e),
|
||||
Junctions::X6(a, b, c, d, e, f) => Junctions::X7(new, a, b, c, d, e, f),
|
||||
Junctions::X7(a, b, c, d, e, f, g) => Junctions::X8(new, a, b, c, d, e, f, g),
|
||||
s => Err((s, new))?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Mutate `self` so that it is suffixed with `suffix`.
|
||||
///
|
||||
/// Does not modify `self` and returns `Err` with `suffix` in case of overflow.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use xcm::v3::{Junctions::*, Junction::*, MultiLocation};
|
||||
/// # fn main() {
|
||||
/// let mut m = X1(Parachain(21));
|
||||
/// assert_eq!(m.append_with(X1(PalletInstance(3))), Ok(()));
|
||||
/// assert_eq!(m, X2(Parachain(21), PalletInstance(3)));
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn append_with(&mut self, suffix: impl Into<Junctions>) -> Result<(), Junctions> {
|
||||
let suffix = suffix.into();
|
||||
if self.len().saturating_add(suffix.len()) > MAX_JUNCTIONS {
|
||||
return Err(suffix)
|
||||
}
|
||||
for j in suffix.into_iter() {
|
||||
self.push(j).expect("Already checked the sum of the len()s; qed")
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the number of junctions in `self`.
|
||||
pub const fn len(&self) -> usize {
|
||||
match &self {
|
||||
Junctions::Here => 0,
|
||||
Junctions::X1(..) => 1,
|
||||
Junctions::X2(..) => 2,
|
||||
Junctions::X3(..) => 3,
|
||||
Junctions::X4(..) => 4,
|
||||
Junctions::X5(..) => 5,
|
||||
Junctions::X6(..) => 6,
|
||||
Junctions::X7(..) => 7,
|
||||
Junctions::X8(..) => 8,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the junction at index `i`, or `None` if the location doesn't contain that many elements.
|
||||
pub fn at(&self, i: usize) -> Option<&Junction> {
|
||||
Some(match (i, self) {
|
||||
(0, Junctions::X1(ref a)) => a,
|
||||
(0, Junctions::X2(ref a, ..)) => a,
|
||||
(0, Junctions::X3(ref a, ..)) => a,
|
||||
(0, Junctions::X4(ref a, ..)) => a,
|
||||
(0, Junctions::X5(ref a, ..)) => a,
|
||||
(0, Junctions::X6(ref a, ..)) => a,
|
||||
(0, Junctions::X7(ref a, ..)) => a,
|
||||
(0, Junctions::X8(ref a, ..)) => a,
|
||||
(1, Junctions::X2(_, ref a)) => a,
|
||||
(1, Junctions::X3(_, ref a, ..)) => a,
|
||||
(1, Junctions::X4(_, ref a, ..)) => a,
|
||||
(1, Junctions::X5(_, ref a, ..)) => a,
|
||||
(1, Junctions::X6(_, ref a, ..)) => a,
|
||||
(1, Junctions::X7(_, ref a, ..)) => a,
|
||||
(1, Junctions::X8(_, ref a, ..)) => a,
|
||||
(2, Junctions::X3(_, _, ref a)) => a,
|
||||
(2, Junctions::X4(_, _, ref a, ..)) => a,
|
||||
(2, Junctions::X5(_, _, ref a, ..)) => a,
|
||||
(2, Junctions::X6(_, _, ref a, ..)) => a,
|
||||
(2, Junctions::X7(_, _, ref a, ..)) => a,
|
||||
(2, Junctions::X8(_, _, ref a, ..)) => a,
|
||||
(3, Junctions::X4(_, _, _, ref a)) => a,
|
||||
(3, Junctions::X5(_, _, _, ref a, ..)) => a,
|
||||
(3, Junctions::X6(_, _, _, ref a, ..)) => a,
|
||||
(3, Junctions::X7(_, _, _, ref a, ..)) => a,
|
||||
(3, Junctions::X8(_, _, _, ref a, ..)) => a,
|
||||
(4, Junctions::X5(_, _, _, _, ref a)) => a,
|
||||
(4, Junctions::X6(_, _, _, _, ref a, ..)) => a,
|
||||
(4, Junctions::X7(_, _, _, _, ref a, ..)) => a,
|
||||
(4, Junctions::X8(_, _, _, _, ref a, ..)) => a,
|
||||
(5, Junctions::X6(_, _, _, _, _, ref a)) => a,
|
||||
(5, Junctions::X7(_, _, _, _, _, ref a, ..)) => a,
|
||||
(5, Junctions::X8(_, _, _, _, _, ref a, ..)) => a,
|
||||
(6, Junctions::X7(_, _, _, _, _, _, ref a)) => a,
|
||||
(6, Junctions::X8(_, _, _, _, _, _, ref a, ..)) => a,
|
||||
(7, Junctions::X8(_, _, _, _, _, _, _, ref a)) => a,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the junction at index `i`, or `None` if the location doesn't contain that many
|
||||
/// elements.
|
||||
pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> {
|
||||
Some(match (i, self) {
|
||||
(0, Junctions::X1(ref mut a)) => a,
|
||||
(0, Junctions::X2(ref mut a, ..)) => a,
|
||||
(0, Junctions::X3(ref mut a, ..)) => a,
|
||||
(0, Junctions::X4(ref mut a, ..)) => a,
|
||||
(0, Junctions::X5(ref mut a, ..)) => a,
|
||||
(0, Junctions::X6(ref mut a, ..)) => a,
|
||||
(0, Junctions::X7(ref mut a, ..)) => a,
|
||||
(0, Junctions::X8(ref mut a, ..)) => a,
|
||||
(1, Junctions::X2(_, ref mut a)) => a,
|
||||
(1, Junctions::X3(_, ref mut a, ..)) => a,
|
||||
(1, Junctions::X4(_, ref mut a, ..)) => a,
|
||||
(1, Junctions::X5(_, ref mut a, ..)) => a,
|
||||
(1, Junctions::X6(_, ref mut a, ..)) => a,
|
||||
(1, Junctions::X7(_, ref mut a, ..)) => a,
|
||||
(1, Junctions::X8(_, ref mut a, ..)) => a,
|
||||
(2, Junctions::X3(_, _, ref mut a)) => a,
|
||||
(2, Junctions::X4(_, _, ref mut a, ..)) => a,
|
||||
(2, Junctions::X5(_, _, ref mut a, ..)) => a,
|
||||
(2, Junctions::X6(_, _, ref mut a, ..)) => a,
|
||||
(2, Junctions::X7(_, _, ref mut a, ..)) => a,
|
||||
(2, Junctions::X8(_, _, ref mut a, ..)) => a,
|
||||
(3, Junctions::X4(_, _, _, ref mut a)) => a,
|
||||
(3, Junctions::X5(_, _, _, ref mut a, ..)) => a,
|
||||
(3, Junctions::X6(_, _, _, ref mut a, ..)) => a,
|
||||
(3, Junctions::X7(_, _, _, ref mut a, ..)) => a,
|
||||
(3, Junctions::X8(_, _, _, ref mut a, ..)) => a,
|
||||
(4, Junctions::X5(_, _, _, _, ref mut a)) => a,
|
||||
(4, Junctions::X6(_, _, _, _, ref mut a, ..)) => a,
|
||||
(4, Junctions::X7(_, _, _, _, ref mut a, ..)) => a,
|
||||
(4, Junctions::X8(_, _, _, _, ref mut a, ..)) => a,
|
||||
(5, Junctions::X6(_, _, _, _, _, ref mut a)) => a,
|
||||
(5, Junctions::X7(_, _, _, _, _, ref mut a, ..)) => a,
|
||||
(5, Junctions::X8(_, _, _, _, _, ref mut a, ..)) => a,
|
||||
(6, Junctions::X7(_, _, _, _, _, _, ref mut a)) => a,
|
||||
(6, Junctions::X8(_, _, _, _, _, _, ref mut a, ..)) => a,
|
||||
(7, Junctions::X8(_, _, _, _, _, _, _, ref mut a)) => a,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns a reference iterator over the junctions.
|
||||
pub fn iter(&self) -> JunctionsRefIterator {
|
||||
JunctionsRefIterator { junctions: self, next: 0, back: 0 }
|
||||
}
|
||||
|
||||
/// Ensures that self begins with `prefix` and that it has a single `Junction` item following.
|
||||
/// If so, returns a reference to this `Junction` item.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use xcm::v3::{Junctions::*, Junction::*};
|
||||
/// # fn main() {
|
||||
/// let mut m = X3(Parachain(2), PalletInstance(3), OnlyChild);
|
||||
/// assert_eq!(m.match_and_split(&X2(Parachain(2), PalletInstance(3))), Some(&OnlyChild));
|
||||
/// assert_eq!(m.match_and_split(&X1(Parachain(2))), None);
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn match_and_split(&self, prefix: &Junctions) -> Option<&Junction> {
|
||||
if prefix.len() + 1 != self.len() {
|
||||
return None
|
||||
}
|
||||
for i in 0..prefix.len() {
|
||||
if prefix.at(i) != self.at(i) {
|
||||
return None
|
||||
}
|
||||
}
|
||||
return self.at(prefix.len())
|
||||
}
|
||||
|
||||
pub fn starts_with(&self, prefix: &Junctions) -> bool {
|
||||
prefix.len() <= self.len() && prefix.iter().zip(self.iter()).all(|(x, y)| x == y)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<MultiLocation> for Junctions {
|
||||
type Error = MultiLocation;
|
||||
fn try_from(x: MultiLocation) -> result::Result<Self, MultiLocation> {
|
||||
if x.parents > 0 {
|
||||
Err(x)
|
||||
} else {
|
||||
Ok(x.interior)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Into<Junction>> From<T> for Junctions {
|
||||
fn from(x: T) -> Self {
|
||||
Self::X1(x.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[Junction; 0]> for Junctions {
|
||||
fn from(_: [Junction; 0]) -> Self {
|
||||
Self::Here
|
||||
}
|
||||
}
|
||||
|
||||
impl From<()> for Junctions {
|
||||
fn from(_: ()) -> Self {
|
||||
Self::Here
|
||||
}
|
||||
}
|
||||
|
||||
xcm_procedural::impl_conversion_functions_for_junctions_v3!();
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{super::prelude::*, *};
|
||||
|
||||
#[test]
|
||||
fn inverting_works() {
|
||||
let context: InteriorMultiLocation = (Parachain(1000), PalletInstance(42)).into();
|
||||
let target = (Parent, PalletInstance(69)).into();
|
||||
let expected = (Parent, PalletInstance(42)).into();
|
||||
let inverted = context.invert_target(&target).unwrap();
|
||||
assert_eq!(inverted, expected);
|
||||
|
||||
let context: InteriorMultiLocation =
|
||||
(Parachain(1000), PalletInstance(42), GeneralIndex(1)).into();
|
||||
let target = (Parent, Parent, PalletInstance(69), GeneralIndex(2)).into();
|
||||
let expected = (Parent, Parent, PalletInstance(42), GeneralIndex(1)).into();
|
||||
let inverted = context.invert_target(&target).unwrap();
|
||||
assert_eq!(inverted, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn relative_to_works() {
|
||||
use Junctions::*;
|
||||
use NetworkId::*;
|
||||
assert_eq!(X1(Polkadot.into()).relative_to(&X1(Kusama.into())), (Parent, Polkadot).into());
|
||||
let base = X3(Kusama.into(), Parachain(1), PalletInstance(1));
|
||||
|
||||
// Ancestors.
|
||||
assert_eq!(Here.relative_to(&base), (Parent, Parent, Parent).into());
|
||||
assert_eq!(X1(Kusama.into()).relative_to(&base), (Parent, Parent).into());
|
||||
assert_eq!(X2(Kusama.into(), Parachain(1)).relative_to(&base), (Parent,).into());
|
||||
assert_eq!(
|
||||
X3(Kusama.into(), Parachain(1), PalletInstance(1)).relative_to(&base),
|
||||
Here.into()
|
||||
);
|
||||
|
||||
// Ancestors with one child.
|
||||
assert_eq!(
|
||||
X1(Polkadot.into()).relative_to(&base),
|
||||
(Parent, Parent, Parent, Polkadot).into()
|
||||
);
|
||||
assert_eq!(
|
||||
X2(Kusama.into(), Parachain(2)).relative_to(&base),
|
||||
(Parent, Parent, Parachain(2)).into()
|
||||
);
|
||||
assert_eq!(
|
||||
X3(Kusama.into(), Parachain(1), PalletInstance(2)).relative_to(&base),
|
||||
(Parent, PalletInstance(2)).into()
|
||||
);
|
||||
assert_eq!(
|
||||
X4(Kusama.into(), Parachain(1), PalletInstance(1), [1u8; 32].into()).relative_to(&base),
|
||||
([1u8; 32],).into()
|
||||
);
|
||||
|
||||
// Ancestors with grandchildren.
|
||||
assert_eq!(
|
||||
X2(Polkadot.into(), Parachain(1)).relative_to(&base),
|
||||
(Parent, Parent, Parent, Polkadot, Parachain(1)).into()
|
||||
);
|
||||
assert_eq!(
|
||||
X3(Kusama.into(), Parachain(2), PalletInstance(1)).relative_to(&base),
|
||||
(Parent, Parent, Parachain(2), PalletInstance(1)).into()
|
||||
);
|
||||
assert_eq!(
|
||||
X4(Kusama.into(), Parachain(1), PalletInstance(2), [1u8; 32].into()).relative_to(&base),
|
||||
(Parent, PalletInstance(2), [1u8; 32]).into()
|
||||
);
|
||||
assert_eq!(
|
||||
X5(Kusama.into(), Parachain(1), PalletInstance(1), [1u8; 32].into(), 1u128.into())
|
||||
.relative_to(&base),
|
||||
([1u8; 32], 1u128).into()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn global_consensus_works() {
|
||||
use Junctions::*;
|
||||
use NetworkId::*;
|
||||
assert_eq!(X1(Polkadot.into()).global_consensus(), Ok(Polkadot));
|
||||
assert_eq!(X2(Kusama.into(), 1u64.into()).global_consensus(), Ok(Kusama));
|
||||
assert_eq!(Here.global_consensus(), Err(()));
|
||||
assert_eq!(X1(1u64.into()).global_consensus(), Err(()));
|
||||
assert_eq!(X2(1u64.into(), Kusama.into()).global_consensus(), Err(()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_conversion() {
|
||||
use super::{Junction::*, Junctions::*, NetworkId::*};
|
||||
let x: Junctions = GlobalConsensus(Polkadot).into();
|
||||
assert_eq!(x, X1(GlobalConsensus(Polkadot)));
|
||||
let x: Junctions = Polkadot.into();
|
||||
assert_eq!(x, X1(GlobalConsensus(Polkadot)));
|
||||
let x: Junctions = (Polkadot, Kusama).into();
|
||||
assert_eq!(x, X2(GlobalConsensus(Polkadot), GlobalConsensus(Kusama)));
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,951 @@
|
||||
// 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::{InteriorMultiLocation, MultiLocation};
|
||||
use crate::v2::{
|
||||
AssetId as OldAssetId, AssetInstance as OldAssetInstance, Fungibility as OldFungibility,
|
||||
MultiAsset as OldMultiAsset, MultiAssetFilter as OldMultiAssetFilter,
|
||||
MultiAssets as OldMultiAssets, WildFungibility as OldWildFungibility,
|
||||
WildMultiAsset as OldWildMultiAsset,
|
||||
};
|
||||
use alloc::{vec, vec::Vec};
|
||||
use core::{
|
||||
cmp::Ordering,
|
||||
convert::{TryFrom, TryInto},
|
||||
};
|
||||
use parity_scale_codec::{self as codec, Decode, Encode, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
/// A general identifier for an instance of a non-fungible asset class.
|
||||
#[derive(
|
||||
Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen,
|
||||
)]
|
||||
#[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]),
|
||||
}
|
||||
|
||||
impl TryFrom<OldAssetInstance> for AssetInstance {
|
||||
type Error = ();
|
||||
fn try_from(value: OldAssetInstance) -> Result<Self, Self::Error> {
|
||||
use OldAssetInstance::*;
|
||||
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),
|
||||
Blob(_) => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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<u8> for AssetInstance {
|
||||
fn from(x: u8) -> Self {
|
||||
Self::Index(x as u128)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u16> for AssetInstance {
|
||||
fn from(x: u16) -> Self {
|
||||
Self::Index(x as u128)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for AssetInstance {
|
||||
fn from(x: u32) -> Self {
|
||||
Self::Index(x as u128)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for AssetInstance {
|
||||
fn from(x: u64) -> Self {
|
||||
Self::Index(x as u128)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<AssetInstance> for () {
|
||||
type Error = ();
|
||||
fn try_from(x: AssetInstance) -> Result<Self, ()> {
|
||||
match x {
|
||||
AssetInstance::Undefined => Ok(()),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<AssetInstance> for [u8; 4] {
|
||||
type Error = ();
|
||||
fn try_from(x: AssetInstance) -> Result<Self, ()> {
|
||||
match x {
|
||||
AssetInstance::Array4(x) => Ok(x),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<AssetInstance> for [u8; 8] {
|
||||
type Error = ();
|
||||
fn try_from(x: AssetInstance) -> Result<Self, ()> {
|
||||
match x {
|
||||
AssetInstance::Array8(x) => Ok(x),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<AssetInstance> for [u8; 16] {
|
||||
type Error = ();
|
||||
fn try_from(x: AssetInstance) -> Result<Self, ()> {
|
||||
match x {
|
||||
AssetInstance::Array16(x) => Ok(x),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<AssetInstance> for [u8; 32] {
|
||||
type Error = ();
|
||||
fn try_from(x: AssetInstance) -> Result<Self, ()> {
|
||||
match x {
|
||||
AssetInstance::Array32(x) => Ok(x),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<AssetInstance> for u8 {
|
||||
type Error = ();
|
||||
fn try_from(x: AssetInstance) -> Result<Self, ()> {
|
||||
match x {
|
||||
AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<AssetInstance> for u16 {
|
||||
type Error = ();
|
||||
fn try_from(x: AssetInstance) -> Result<Self, ()> {
|
||||
match x {
|
||||
AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<AssetInstance> for u32 {
|
||||
type Error = ();
|
||||
fn try_from(x: AssetInstance) -> Result<Self, ()> {
|
||||
match x {
|
||||
AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<AssetInstance> for u64 {
|
||||
type Error = ();
|
||||
fn try_from(x: AssetInstance) -> Result<Self, ()> {
|
||||
match x {
|
||||
AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<AssetInstance> for u128 {
|
||||
type Error = ();
|
||||
fn try_from(x: AssetInstance) -> Result<Self, ()> {
|
||||
match x {
|
||||
AssetInstance::Index(x) => Ok(x),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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, MaxEncodedLen)]
|
||||
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum Fungibility {
|
||||
/// A fungible asset; we record a number of units, as a `u128` in the inner item.
|
||||
Fungible(#[codec(compact)] u128),
|
||||
/// A non-fungible asset. We record the instance identifier in the inner item. Only one asset
|
||||
/// of each instance identifier may ever be in existence at once.
|
||||
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<i32> for Fungibility {
|
||||
fn from(amount: i32) -> Fungibility {
|
||||
debug_assert_ne!(amount, 0);
|
||||
Fungibility::Fungible(amount as u128)
|
||||
}
|
||||
}
|
||||
|
||||
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<OldFungibility> for Fungibility {
|
||||
type Error = ();
|
||||
fn try_from(value: OldFungibility) -> Result<Self, Self::Error> {
|
||||
use OldFungibility::*;
|
||||
Ok(match value {
|
||||
Fungible(n) => Self::Fungible(n),
|
||||
NonFungible(i) => Self::NonFungible(i.try_into()?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Classification of whether an asset is fungible or not.
|
||||
#[derive(
|
||||
Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo, MaxEncodedLen,
|
||||
)]
|
||||
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum WildFungibility {
|
||||
/// The asset is fungible.
|
||||
Fungible,
|
||||
/// The asset is not fungible.
|
||||
NonFungible,
|
||||
}
|
||||
|
||||
impl TryFrom<OldWildFungibility> for WildFungibility {
|
||||
type Error = ();
|
||||
fn try_from(value: OldWildFungibility) -> Result<Self, Self::Error> {
|
||||
use OldWildFungibility::*;
|
||||
Ok(match value {
|
||||
Fungible => Self::Fungible,
|
||||
NonFungible => Self::NonFungible,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Classification of an asset being concrete or abstract.
|
||||
#[derive(
|
||||
Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo, MaxEncodedLen,
|
||||
)]
|
||||
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum AssetId {
|
||||
/// A specific location identifying an asset.
|
||||
Concrete(MultiLocation),
|
||||
/// An abstract location; this is a name which may mean different specific locations on
|
||||
/// different chains at different times.
|
||||
Abstract([u8; 32]),
|
||||
}
|
||||
|
||||
impl<T: Into<MultiLocation>> From<T> for AssetId {
|
||||
fn from(x: T) -> Self {
|
||||
Self::Concrete(x.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[u8; 32]> for AssetId {
|
||||
fn from(x: [u8; 32]) -> Self {
|
||||
Self::Abstract(x)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<OldAssetId> for AssetId {
|
||||
type Error = ();
|
||||
fn try_from(old: OldAssetId) -> Result<Self, ()> {
|
||||
use OldAssetId::*;
|
||||
Ok(match old {
|
||||
Concrete(l) => Self::Concrete(l.try_into()?),
|
||||
Abstract(v) if v.len() <= 32 => {
|
||||
let mut r = [0u8; 32];
|
||||
r[..v.len()].copy_from_slice(&v[..]);
|
||||
Self::Abstract(r)
|
||||
},
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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).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 `context`.
|
||||
pub fn reanchor(
|
||||
&mut self,
|
||||
target: &MultiLocation,
|
||||
context: InteriorMultiLocation,
|
||||
) -> Result<(), ()> {
|
||||
if let AssetId::Concrete(ref mut l) = self {
|
||||
l.reanchor(target, context)?;
|
||||
}
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
||||
/// Either an amount of a single fungible asset, or a single well-identified non-fungible asset.
|
||||
#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)]
|
||||
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct MultiAsset {
|
||||
/// The overall asset identity (aka *class*, in the case of a non-fungible).
|
||||
pub id: AssetId,
|
||||
/// The fungibility of the asset, which contains either the amount (in the case of a fungible
|
||||
/// asset) or the *insance ID`, the secondary asset identifier.
|
||||
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 `context`.
|
||||
pub fn reanchor(
|
||||
&mut self,
|
||||
target: &MultiLocation,
|
||||
context: InteriorMultiLocation,
|
||||
) -> Result<(), ()> {
|
||||
self.id.reanchor(target, context)
|
||||
}
|
||||
|
||||
/// 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 `context`.
|
||||
pub fn reanchored(
|
||||
mut self,
|
||||
target: &MultiLocation,
|
||||
context: InteriorMultiLocation,
|
||||
) -> Result<Self, ()> {
|
||||
self.id.reanchor(target, context)?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Returns true if `self` is a super-set of the given `inner` asset.
|
||||
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<OldMultiAsset> for MultiAsset {
|
||||
type Error = ();
|
||||
fn try_from(old: OldMultiAsset) -> Result<Self, ()> {
|
||||
Ok(Self { id: old.id.try_into()?, fun: old.fun.try_into()? })
|
||||
}
|
||||
}
|
||||
|
||||
/// A `Vec` of `MultiAsset`s.
|
||||
///
|
||||
/// There are a number of invariants which the construction and mutation functions must ensure are
|
||||
/// maintained:
|
||||
/// - It may contain no items of duplicate asset class;
|
||||
/// - All items must be ordered;
|
||||
/// - The number of items should grow no larger than `MAX_ITEMS_IN_MULTIASSETS`.
|
||||
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, TypeInfo, Default)]
|
||||
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct MultiAssets(Vec<MultiAsset>);
|
||||
|
||||
/// Maximum number of items we expect in a single `MultiAssets` value. Note this is not (yet)
|
||||
/// enforced, and just serves to provide a sensible `max_encoded_len` for `MultiAssets`.
|
||||
const MAX_ITEMS_IN_MULTIASSETS: usize = 20;
|
||||
|
||||
impl MaxEncodedLen for MultiAssets {
|
||||
fn max_encoded_len() -> usize {
|
||||
MultiAsset::max_encoded_len() * MAX_ITEMS_IN_MULTIASSETS
|
||||
}
|
||||
}
|
||||
|
||||
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<OldMultiAssets> for MultiAssets {
|
||||
type Error = ();
|
||||
fn try_from(old: OldMultiAssets) -> Result<Self, ()> {
|
||||
let v = old
|
||||
.drain()
|
||||
.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) {
|
||||
for asset in self.0.iter_mut().filter(|x| x.id == a.id) {
|
||||
match (&a.fun, &mut asset.fun) {
|
||||
(Fungibility::Fungible(amount), Fungibility::Fungible(balance)) => {
|
||||
*balance = balance.saturating_add(*amount);
|
||||
return
|
||||
},
|
||||
(Fungibility::NonFungible(inst1), Fungibility::NonFungible(inst2))
|
||||
if inst1 == inst2 =>
|
||||
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` asset.
|
||||
pub fn contains(&self, inner: &MultiAsset) -> bool {
|
||||
self.0.iter().any(|i| i.contains(inner))
|
||||
}
|
||||
|
||||
/// Consume `self` and return the inner vec.
|
||||
#[deprecated = "Use `into_inner()` instead"]
|
||||
pub fn drain(self) -> Vec<MultiAsset> {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Consume `self` and return the inner vec.
|
||||
pub fn into_inner(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 `context`.
|
||||
pub fn reanchor(
|
||||
&mut self,
|
||||
target: &MultiLocation,
|
||||
context: InteriorMultiLocation,
|
||||
) -> Result<(), ()> {
|
||||
self.0.iter_mut().try_for_each(|i| i.reanchor(target, context))
|
||||
}
|
||||
|
||||
/// 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)
|
||||
}
|
||||
}
|
||||
|
||||
/// A wildcard representing a set of assets.
|
||||
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)]
|
||||
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum WildMultiAsset {
|
||||
/// All assets in Holding.
|
||||
All,
|
||||
/// All assets in Holding of a given fungibility and ID.
|
||||
AllOf { id: AssetId, fun: WildFungibility },
|
||||
/// All assets in Holding, up to `u32` individual assets (different instances of non-fungibles
|
||||
/// are separate assets).
|
||||
AllCounted(#[codec(compact)] u32),
|
||||
/// All assets in Holding of a given fungibility and ID up to `count` individual assets
|
||||
/// (different instances of non-fungibles are separate assets).
|
||||
AllOfCounted {
|
||||
id: AssetId,
|
||||
fun: WildFungibility,
|
||||
#[codec(compact)]
|
||||
count: u32,
|
||||
},
|
||||
}
|
||||
|
||||
impl TryFrom<OldWildMultiAsset> for WildMultiAsset {
|
||||
type Error = ();
|
||||
fn try_from(old: OldWildMultiAsset) -> Result<WildMultiAsset, ()> {
|
||||
use OldWildMultiAsset::*;
|
||||
Ok(match old {
|
||||
AllOf { id, fun } => Self::AllOf { id: id.try_into()?, fun: fun.try_into()? },
|
||||
All => Self::All,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<(OldWildMultiAsset, u32)> for WildMultiAsset {
|
||||
type Error = ();
|
||||
fn try_from(old: (OldWildMultiAsset, u32)) -> Result<WildMultiAsset, ()> {
|
||||
use OldWildMultiAsset::*;
|
||||
let count = old.1;
|
||||
Ok(match old.0 {
|
||||
AllOf { id, fun } =>
|
||||
Self::AllOfCounted { id: id.try_into()?, fun: fun.try_into()?, count },
|
||||
All => Self::AllCounted(count),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl WildMultiAsset {
|
||||
/// Returns true if `self` is a super-set of the given `inner` asset.
|
||||
pub fn contains(&self, inner: &MultiAsset) -> bool {
|
||||
use WildMultiAsset::*;
|
||||
match self {
|
||||
AllOfCounted { count: 0, .. } | AllCounted(0) => false,
|
||||
AllOf { fun, id } | AllOfCounted { id, fun, .. } =>
|
||||
inner.fun.is_kind(*fun) && &inner.id == id,
|
||||
All | AllCounted(_) => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the wild element of `self` matches `inner`.
|
||||
///
|
||||
/// Note that for `Counted` variants of wildcards, then it will disregard the count except for
|
||||
/// always returning `false` when equal to 0.
|
||||
#[deprecated = "Use `contains` instead"]
|
||||
pub fn matches(&self, inner: &MultiAsset) -> bool {
|
||||
self.contains(inner)
|
||||
}
|
||||
|
||||
/// Mutate the asset to represent the same value from the perspective of a new `target`
|
||||
/// location. The local chain's location is provided in `context`.
|
||||
pub fn reanchor(
|
||||
&mut self,
|
||||
target: &MultiLocation,
|
||||
context: InteriorMultiLocation,
|
||||
) -> Result<(), ()> {
|
||||
use WildMultiAsset::*;
|
||||
match self {
|
||||
AllOf { ref mut id, .. } | AllOfCounted { ref mut id, .. } =>
|
||||
id.reanchor(target, context),
|
||||
All | AllCounted(_) => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Maximum count of assets allowed to match, if any.
|
||||
pub fn count(&self) -> Option<u32> {
|
||||
use WildMultiAsset::*;
|
||||
match self {
|
||||
AllOfCounted { count, .. } | AllCounted(count) => Some(*count),
|
||||
All | AllOf { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Explicit limit on number of assets allowed to match, if any.
|
||||
pub fn limit(&self) -> Option<u32> {
|
||||
self.count()
|
||||
}
|
||||
|
||||
/// Consume self and return the equivalent version but counted and with the `count` set to the
|
||||
/// given parameter.
|
||||
pub fn counted(self, count: u32) -> Self {
|
||||
use WildMultiAsset::*;
|
||||
match self {
|
||||
AllOfCounted { fun, id, .. } | AllOf { fun, id } => AllOfCounted { fun, id, count },
|
||||
All | AllCounted(_) => AllCounted(count),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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, defined either by a number of `MultiAssets` or a single wildcard.
|
||||
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)]
|
||||
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum MultiAssetFilter {
|
||||
/// Specify the filter as being everything contained by the given `MultiAssets` inner.
|
||||
Definite(MultiAssets),
|
||||
/// Specify the filter as the given `WildMultiAsset` wildcard.
|
||||
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 `inner` would be matched by `self`.
|
||||
///
|
||||
/// Note that for `Counted` variants of wildcards, then it will disregard the count except for
|
||||
/// always returning `false` when equal to 0.
|
||||
pub fn matches(&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 `context`.
|
||||
pub fn reanchor(
|
||||
&mut self,
|
||||
target: &MultiLocation,
|
||||
context: InteriorMultiLocation,
|
||||
) -> Result<(), ()> {
|
||||
match self {
|
||||
MultiAssetFilter::Definite(ref mut assets) => assets.reanchor(target, context),
|
||||
MultiAssetFilter::Wild(ref mut wild) => wild.reanchor(target, context),
|
||||
}
|
||||
}
|
||||
|
||||
/// Maximum count of assets it is possible to match, if known.
|
||||
pub fn count(&self) -> Option<u32> {
|
||||
use MultiAssetFilter::*;
|
||||
match self {
|
||||
Definite(x) => Some(x.len() as u32),
|
||||
Wild(x) => x.count(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Explicit limit placed on the number of items, if any.
|
||||
pub fn limit(&self) -> Option<u32> {
|
||||
use MultiAssetFilter::*;
|
||||
match self {
|
||||
Definite(_) => None,
|
||||
Wild(x) => x.limit(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<OldMultiAssetFilter> for MultiAssetFilter {
|
||||
type Error = ();
|
||||
fn try_from(old: OldMultiAssetFilter) -> Result<MultiAssetFilter, ()> {
|
||||
Ok(match old {
|
||||
OldMultiAssetFilter::Definite(x) => Self::Definite(x.try_into()?),
|
||||
OldMultiAssetFilter::Wild(x) => Self::Wild(x.try_into()?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<(OldMultiAssetFilter, u32)> for MultiAssetFilter {
|
||||
type Error = ();
|
||||
fn try_from(old: (OldMultiAssetFilter, u32)) -> Result<MultiAssetFilter, ()> {
|
||||
let count = old.1;
|
||||
Ok(match old.0 {
|
||||
OldMultiAssetFilter::Definite(x) if count >= x.len() as u32 =>
|
||||
Self::Definite(x.try_into()?),
|
||||
OldMultiAssetFilter::Wild(x) => Self::Wild((x, count).try_into()?),
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::prelude::*;
|
||||
|
||||
#[test]
|
||||
fn conversion_works() {
|
||||
let _: MultiAssets = (Here, 1u128).into();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_sorted_and_deduplicated_works() {
|
||||
use super::*;
|
||||
use alloc::vec;
|
||||
|
||||
let empty = vec![];
|
||||
let r = MultiAssets::from_sorted_and_deduplicated(empty);
|
||||
assert_eq!(r, Ok(MultiAssets(vec![])));
|
||||
|
||||
let dup_fun = vec![(Here, 100).into(), (Here, 10).into()];
|
||||
let r = MultiAssets::from_sorted_and_deduplicated(dup_fun);
|
||||
assert!(r.is_err());
|
||||
|
||||
let dup_nft = vec![(Here, *b"notgood!").into(), (Here, *b"notgood!").into()];
|
||||
let r = MultiAssets::from_sorted_and_deduplicated(dup_nft);
|
||||
assert!(r.is_err());
|
||||
|
||||
let good_fun = vec![(Here, 10).into(), (Parent, 10).into()];
|
||||
let r = MultiAssets::from_sorted_and_deduplicated(good_fun.clone());
|
||||
assert_eq!(r, Ok(MultiAssets(good_fun)));
|
||||
|
||||
let bad_fun = vec![(Parent, 10).into(), (Here, 10).into()];
|
||||
let r = MultiAssets::from_sorted_and_deduplicated(bad_fun);
|
||||
assert!(r.is_err());
|
||||
|
||||
let good_abstract_fun = vec![(Here, 100).into(), ([0u8; 32], 10).into()];
|
||||
let r = MultiAssets::from_sorted_and_deduplicated(good_abstract_fun.clone());
|
||||
assert_eq!(r, Ok(MultiAssets(good_abstract_fun)));
|
||||
|
||||
let bad_abstract_fun = vec![([0u8; 32], 10).into(), (Here, 10).into()];
|
||||
let r = MultiAssets::from_sorted_and_deduplicated(bad_abstract_fun);
|
||||
assert!(r.is_err());
|
||||
|
||||
let good_nft = vec![(Here, ()).into(), (Here, *b"good").into()];
|
||||
let r = MultiAssets::from_sorted_and_deduplicated(good_nft.clone());
|
||||
assert_eq!(r, Ok(MultiAssets(good_nft)));
|
||||
|
||||
let bad_nft = vec![(Here, *b"bad!").into(), (Here, ()).into()];
|
||||
let r = MultiAssets::from_sorted_and_deduplicated(bad_nft);
|
||||
assert!(r.is_err());
|
||||
|
||||
let good_abstract_nft = vec![(Here, ()).into(), ([0u8; 32], ()).into()];
|
||||
let r = MultiAssets::from_sorted_and_deduplicated(good_abstract_nft.clone());
|
||||
assert_eq!(r, Ok(MultiAssets(good_abstract_nft)));
|
||||
|
||||
let bad_abstract_nft = vec![([0u8; 32], ()).into(), (Here, ()).into()];
|
||||
let r = MultiAssets::from_sorted_and_deduplicated(bad_abstract_nft);
|
||||
assert!(r.is_err());
|
||||
|
||||
let mixed_good = vec![(Here, 10).into(), (Here, *b"good").into()];
|
||||
let r = MultiAssets::from_sorted_and_deduplicated(mixed_good.clone());
|
||||
assert_eq!(r, Ok(MultiAssets(mixed_good)));
|
||||
|
||||
let mixed_bad = vec![(Here, *b"bad!").into(), (Here, 10).into()];
|
||||
let r = MultiAssets::from_sorted_and_deduplicated(mixed_bad);
|
||||
assert!(r.is_err());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,710 @@
|
||||
// Copyright 2020-2021 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/>.
|
||||
|
||||
//! XCM `MultiLocation` datatype.
|
||||
|
||||
use super::{Junction, Junctions};
|
||||
use crate::{v2::MultiLocation as OldMultiLocation, VersionedMultiLocation};
|
||||
use core::{
|
||||
convert::{TryFrom, TryInto},
|
||||
result,
|
||||
};
|
||||
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
/// A relative path between state-bearing consensus systems.
|
||||
///
|
||||
/// A location in a consensus system is defined as an *isolatable state machine* held within global
|
||||
/// consensus. The location in question need not have a sophisticated consensus algorithm of its
|
||||
/// own; a single account within Ethereum, for example, could be considered a location.
|
||||
///
|
||||
/// A very-much non-exhaustive list of types of location include:
|
||||
/// - A (normal, layer-1) block chain, e.g. the Bitcoin mainnet or a parachain.
|
||||
/// - A layer-0 super-chain, e.g. the Polkadot Relay chain.
|
||||
/// - A layer-2 smart contract, e.g. an ERC-20 on Ethereum.
|
||||
/// - A logical functional component of a chain, e.g. a single instance of a pallet on a Frame-based
|
||||
/// Substrate chain.
|
||||
/// - An account.
|
||||
///
|
||||
/// A `MultiLocation` is a *relative identifier*, meaning that it can only be used to define the
|
||||
/// relative path between two locations, and cannot generally be used to refer to a location
|
||||
/// universally. It is comprised of an integer number of parents specifying the number of times to
|
||||
/// "escape" upwards into the containing consensus system and then a number of *junctions*, each
|
||||
/// diving down and specifying some interior portion of state (which may be considered a
|
||||
/// "sub-consensus" system).
|
||||
///
|
||||
/// This specific `MultiLocation` implementation uses a `Junctions` datatype which is a Rust `enum`
|
||||
/// in order to make pattern matching easier. There are occasions where it is important to ensure
|
||||
/// that a value is strictly an interior location, in those cases, `Junctions` may be used.
|
||||
///
|
||||
/// The `MultiLocation` value of `Null` simply refers to the interpreting consensus system.
|
||||
#[derive(
|
||||
Copy, Clone, Decode, Encode, Eq, PartialEq, Ord, PartialOrd, Debug, TypeInfo, MaxEncodedLen,
|
||||
)]
|
||||
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct MultiLocation {
|
||||
/// The number of parent junctions at the beginning of this `MultiLocation`.
|
||||
pub parents: u8,
|
||||
/// The interior (i.e. non-parent) junctions that this `MultiLocation` contains.
|
||||
pub interior: Junctions,
|
||||
}
|
||||
|
||||
impl Default for MultiLocation {
|
||||
fn default() -> Self {
|
||||
Self { parents: 0, interior: Junctions::Here }
|
||||
}
|
||||
}
|
||||
|
||||
/// A relative location which is constrained to be an interior location of the context.
|
||||
///
|
||||
/// See also `MultiLocation`.
|
||||
pub type InteriorMultiLocation = Junctions;
|
||||
|
||||
impl MultiLocation {
|
||||
/// Creates a new `MultiLocation` with the given number of parents and interior junctions.
|
||||
pub fn new(parents: u8, interior: impl Into<Junctions>) -> MultiLocation {
|
||||
MultiLocation { parents, interior: interior.into() }
|
||||
}
|
||||
|
||||
/// Consume `self` and return the equivalent `VersionedMultiLocation` value.
|
||||
pub const fn into_versioned(self) -> VersionedMultiLocation {
|
||||
VersionedMultiLocation::V3(self)
|
||||
}
|
||||
|
||||
/// Creates a new `MultiLocation` with 0 parents and a `Here` interior.
|
||||
///
|
||||
/// The resulting `MultiLocation` can be interpreted as the "current consensus system".
|
||||
pub const fn here() -> MultiLocation {
|
||||
MultiLocation { parents: 0, interior: Junctions::Here }
|
||||
}
|
||||
|
||||
/// Creates a new `MultiLocation` which evaluates to the parent context.
|
||||
pub const fn parent() -> MultiLocation {
|
||||
MultiLocation { parents: 1, interior: Junctions::Here }
|
||||
}
|
||||
|
||||
/// Creates a new `MultiLocation` which evaluates to the grand parent context.
|
||||
pub const fn grandparent() -> MultiLocation {
|
||||
MultiLocation { parents: 2, interior: Junctions::Here }
|
||||
}
|
||||
|
||||
/// Creates a new `MultiLocation` with `parents` and an empty (`Here`) interior.
|
||||
pub const fn ancestor(parents: u8) -> MultiLocation {
|
||||
MultiLocation { parents, interior: Junctions::Here }
|
||||
}
|
||||
|
||||
/// Whether the `MultiLocation` has no parents and has a `Here` interior.
|
||||
pub const fn is_here(&self) -> bool {
|
||||
self.parents == 0 && self.interior.len() == 0
|
||||
}
|
||||
|
||||
/// Remove the `NetworkId` value in any interior `Junction`s.
|
||||
pub fn remove_network_id(&mut self) {
|
||||
self.interior.remove_network_id();
|
||||
}
|
||||
|
||||
/// Return a reference to the interior field.
|
||||
pub fn interior(&self) -> &Junctions {
|
||||
&self.interior
|
||||
}
|
||||
|
||||
/// Return a mutable reference to the interior field.
|
||||
pub fn interior_mut(&mut self) -> &mut Junctions {
|
||||
&mut self.interior
|
||||
}
|
||||
|
||||
/// Returns the number of `Parent` junctions at the beginning of `self`.
|
||||
pub const fn parent_count(&self) -> u8 {
|
||||
self.parents
|
||||
}
|
||||
|
||||
/// Returns boolean indicating whether `self` contains only the specified amount of
|
||||
/// parents and no interior junctions.
|
||||
pub const fn contains_parents_only(&self, count: u8) -> bool {
|
||||
matches!(self.interior, Junctions::Here) && self.parents == count
|
||||
}
|
||||
|
||||
/// Returns the number of parents and junctions in `self`.
|
||||
pub const fn len(&self) -> usize {
|
||||
self.parent_count() as usize + self.interior.len()
|
||||
}
|
||||
|
||||
/// Returns the first interior junction, or `None` if the location is empty or contains only
|
||||
/// parents.
|
||||
pub fn first_interior(&self) -> Option<&Junction> {
|
||||
self.interior.first()
|
||||
}
|
||||
|
||||
/// Returns last junction, or `None` if the location is empty or contains only parents.
|
||||
pub fn last(&self) -> Option<&Junction> {
|
||||
self.interior.last()
|
||||
}
|
||||
|
||||
/// Splits off the first interior junction, returning the remaining suffix (first item in tuple)
|
||||
/// and the first element (second item in tuple) or `None` if it was empty.
|
||||
pub fn split_first_interior(self) -> (MultiLocation, Option<Junction>) {
|
||||
let MultiLocation { parents, interior: junctions } = self;
|
||||
let (suffix, first) = junctions.split_first();
|
||||
let multilocation = MultiLocation { parents, interior: suffix };
|
||||
(multilocation, first)
|
||||
}
|
||||
|
||||
/// Splits off the last interior junction, returning the remaining prefix (first item in tuple)
|
||||
/// and the last element (second item in tuple) or `None` if it was empty or if `self` only
|
||||
/// contains parents.
|
||||
pub fn split_last_interior(self) -> (MultiLocation, Option<Junction>) {
|
||||
let MultiLocation { parents, interior: junctions } = self;
|
||||
let (prefix, last) = junctions.split_last();
|
||||
let multilocation = MultiLocation { parents, interior: prefix };
|
||||
(multilocation, last)
|
||||
}
|
||||
|
||||
/// Mutates `self`, suffixing its interior junctions with `new`. Returns `Err` with `new` in
|
||||
/// case of overflow.
|
||||
pub fn push_interior(&mut self, new: impl Into<Junction>) -> result::Result<(), Junction> {
|
||||
self.interior.push(new)
|
||||
}
|
||||
|
||||
/// Mutates `self`, prefixing its interior junctions with `new`. Returns `Err` with `new` in
|
||||
/// case of overflow.
|
||||
pub fn push_front_interior(
|
||||
&mut self,
|
||||
new: impl Into<Junction>,
|
||||
) -> result::Result<(), Junction> {
|
||||
self.interior.push_front(new)
|
||||
}
|
||||
|
||||
/// Consumes `self` and returns a `MultiLocation` suffixed with `new`, or an `Err` with theoriginal value of
|
||||
/// `self` in case of overflow.
|
||||
pub fn pushed_with_interior(
|
||||
self,
|
||||
new: impl Into<Junction>,
|
||||
) -> result::Result<Self, (Self, Junction)> {
|
||||
match self.interior.pushed_with(new) {
|
||||
Ok(i) => Ok(MultiLocation { interior: i, parents: self.parents }),
|
||||
Err((i, j)) => Err((MultiLocation { interior: i, parents: self.parents }, j)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Consumes `self` and returns a `MultiLocation` prefixed with `new`, or an `Err` with the original value of
|
||||
/// `self` in case of overflow.
|
||||
pub fn pushed_front_with_interior(
|
||||
self,
|
||||
new: impl Into<Junction>,
|
||||
) -> result::Result<Self, (Self, Junction)> {
|
||||
match self.interior.pushed_front_with(new) {
|
||||
Ok(i) => Ok(MultiLocation { interior: i, parents: self.parents }),
|
||||
Err((i, j)) => Err((MultiLocation { interior: i, parents: self.parents }, j)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the junction at index `i`, or `None` if the location is a parent or if the location
|
||||
/// does not contain that many elements.
|
||||
pub fn at(&self, i: usize) -> Option<&Junction> {
|
||||
let num_parents = self.parents as usize;
|
||||
if i < num_parents {
|
||||
return None
|
||||
}
|
||||
self.interior.at(i - num_parents)
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the junction at index `i`, or `None` if the location is a
|
||||
/// parent or if it doesn't contain that many elements.
|
||||
pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> {
|
||||
let num_parents = self.parents as usize;
|
||||
if i < num_parents {
|
||||
return None
|
||||
}
|
||||
self.interior.at_mut(i - num_parents)
|
||||
}
|
||||
|
||||
/// Decrements the parent count by 1.
|
||||
pub fn dec_parent(&mut self) {
|
||||
self.parents = self.parents.saturating_sub(1);
|
||||
}
|
||||
|
||||
/// Removes the first interior junction from `self`, returning it
|
||||
/// (or `None` if it was empty or if `self` contains only parents).
|
||||
pub fn take_first_interior(&mut self) -> Option<Junction> {
|
||||
self.interior.take_first()
|
||||
}
|
||||
|
||||
/// Removes the last element from `interior`, returning it (or `None` if it was empty or if
|
||||
/// `self` only contains parents).
|
||||
pub fn take_last(&mut self) -> Option<Junction> {
|
||||
self.interior.take_last()
|
||||
}
|
||||
|
||||
/// Ensures that `self` has the same number of parents as `prefix`, its junctions begins with
|
||||
/// the junctions of `prefix` and that it has a single `Junction` item following.
|
||||
/// If so, returns a reference to this `Junction` item.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use xcm::v3::{Junctions::*, Junction::*, MultiLocation};
|
||||
/// # fn main() {
|
||||
/// let mut m = MultiLocation::new(1, X2(PalletInstance(3), OnlyChild));
|
||||
/// assert_eq!(
|
||||
/// m.match_and_split(&MultiLocation::new(1, X1(PalletInstance(3)))),
|
||||
/// Some(&OnlyChild),
|
||||
/// );
|
||||
/// assert_eq!(m.match_and_split(&MultiLocation::new(1, Here)), None);
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn match_and_split(&self, prefix: &MultiLocation) -> Option<&Junction> {
|
||||
if self.parents != prefix.parents {
|
||||
return None
|
||||
}
|
||||
self.interior.match_and_split(&prefix.interior)
|
||||
}
|
||||
|
||||
pub fn starts_with(&self, prefix: &MultiLocation) -> bool {
|
||||
self.parents == prefix.parents && self.interior.starts_with(&prefix.interior)
|
||||
}
|
||||
|
||||
/// Mutate `self` so that it is suffixed with `suffix`.
|
||||
///
|
||||
/// Does not modify `self` and returns `Err` with `suffix` in case of overflow.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use xcm::v3::{Junctions::*, Junction::*, MultiLocation, Parent};
|
||||
/// # fn main() {
|
||||
/// let mut m: MultiLocation = (Parent, Parachain(21), 69u64).into();
|
||||
/// assert_eq!(m.append_with((Parent, PalletInstance(3))), Ok(()));
|
||||
/// assert_eq!(m, MultiLocation::new(1, X2(Parachain(21), PalletInstance(3))));
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn append_with(&mut self, suffix: impl Into<Self>) -> Result<(), Self> {
|
||||
let prefix = core::mem::replace(self, suffix.into());
|
||||
match self.prepend_with(prefix) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(prefix) => Err(core::mem::replace(self, prefix)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Consume `self` and return its value suffixed with `suffix`.
|
||||
///
|
||||
/// Returns `Err` with the original value of `self` and `suffix` in case of overflow.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use xcm::v3::{Junctions::*, Junction::*, MultiLocation, Parent};
|
||||
/// # fn main() {
|
||||
/// let mut m: MultiLocation = (Parent, Parachain(21), 69u64).into();
|
||||
/// let r = m.appended_with((Parent, PalletInstance(3))).unwrap();
|
||||
/// assert_eq!(r, MultiLocation::new(1, X2(Parachain(21), PalletInstance(3))));
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn appended_with(mut self, suffix: impl Into<Self>) -> Result<Self, (Self, Self)> {
|
||||
match self.append_with(suffix) {
|
||||
Ok(()) => Ok(self),
|
||||
Err(suffix) => Err((self, suffix)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Mutate `self` so that it is prefixed with `prefix`.
|
||||
///
|
||||
/// Does not modify `self` and returns `Err` with `prefix` in case of overflow.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use xcm::v3::{Junctions::*, Junction::*, MultiLocation, Parent};
|
||||
/// # fn main() {
|
||||
/// let mut m: MultiLocation = (Parent, Parent, PalletInstance(3)).into();
|
||||
/// assert_eq!(m.prepend_with((Parent, Parachain(21), OnlyChild)), Ok(()));
|
||||
/// assert_eq!(m, MultiLocation::new(1, X1(PalletInstance(3))));
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn prepend_with(&mut self, prefix: impl Into<Self>) -> Result<(), Self> {
|
||||
// prefix self (suffix)
|
||||
// P .. P I .. I p .. p i .. i
|
||||
let mut prefix = prefix.into();
|
||||
let prepend_interior = prefix.interior.len().saturating_sub(self.parents as usize);
|
||||
let final_interior = self.interior.len().saturating_add(prepend_interior);
|
||||
if final_interior > super::junctions::MAX_JUNCTIONS {
|
||||
return Err(prefix)
|
||||
}
|
||||
let suffix_parents = (self.parents as usize).saturating_sub(prefix.interior.len());
|
||||
let final_parents = (prefix.parents as usize).saturating_add(suffix_parents);
|
||||
if final_parents > 255 {
|
||||
return Err(prefix)
|
||||
}
|
||||
|
||||
// cancel out the final item on the prefix interior for one of the suffix's parents.
|
||||
while self.parents > 0 && prefix.take_last().is_some() {
|
||||
self.dec_parent();
|
||||
}
|
||||
|
||||
// now we have either removed all suffix's parents or prefix interior.
|
||||
// this means we can combine the prefix's and suffix's remaining parents/interior since
|
||||
// we know that with at least one empty, the overall order will be respected:
|
||||
// prefix self (suffix)
|
||||
// P .. P (I) p .. p i .. i => P + p .. (no I) i
|
||||
// -- or --
|
||||
// P .. P I .. I (p) i .. i => P (no p) .. I + i
|
||||
|
||||
self.parents = self.parents.saturating_add(prefix.parents);
|
||||
for j in prefix.interior.into_iter().rev() {
|
||||
self.push_front_interior(j)
|
||||
.expect("final_interior no greater than MAX_JUNCTIONS; qed");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Consume `self` and return its value prefixed with `prefix`.
|
||||
///
|
||||
/// Returns `Err` with the original value of `self` and `prefix` in case of overflow.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use xcm::v3::{Junctions::*, Junction::*, MultiLocation, Parent};
|
||||
/// # fn main() {
|
||||
/// let m: MultiLocation = (Parent, Parent, PalletInstance(3)).into();
|
||||
/// let r = m.prepended_with((Parent, Parachain(21), OnlyChild)).unwrap();
|
||||
/// assert_eq!(r, MultiLocation::new(1, X1(PalletInstance(3))));
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn prepended_with(mut self, prefix: impl Into<Self>) -> Result<Self, (Self, Self)> {
|
||||
match self.prepend_with(prefix) {
|
||||
Ok(()) => Ok(self),
|
||||
Err(prefix) => Err((self, prefix)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Mutate `self` so that it represents the same location from the point of view of `target`.
|
||||
/// The context of `self` is provided as `context`.
|
||||
///
|
||||
/// Does not modify `self` in case of overflow.
|
||||
pub fn reanchor(
|
||||
&mut self,
|
||||
target: &MultiLocation,
|
||||
context: InteriorMultiLocation,
|
||||
) -> Result<(), ()> {
|
||||
// TODO: https://github.com/paritytech/polkadot/issues/4489 Optimize this.
|
||||
|
||||
// 1. Use our `context` to figure out how the `target` would address us.
|
||||
let inverted_target = context.invert_target(target)?;
|
||||
|
||||
// 2. Prepend `inverted_target` to `self` to get self's location from the perspective of
|
||||
// `target`.
|
||||
self.prepend_with(inverted_target).map_err(|_| ())?;
|
||||
|
||||
// 3. Given that we know some of `target` context, ensure that any parents in `self` are
|
||||
// strictly needed.
|
||||
self.simplify(target.interior());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Consume `self` and return a new value representing the same location from the point of view
|
||||
/// of `target`. The context of `self` is provided as `context`.
|
||||
///
|
||||
/// Returns the original `self` in case of overflow.
|
||||
pub fn reanchored(
|
||||
mut self,
|
||||
target: &MultiLocation,
|
||||
context: InteriorMultiLocation,
|
||||
) -> Result<Self, Self> {
|
||||
match self.reanchor(target, context) {
|
||||
Ok(()) => Ok(self),
|
||||
Err(()) => Err(self),
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove any unneeded parents/junctions in `self` based on the given context it will be
|
||||
/// interpreted in.
|
||||
pub fn simplify(&mut self, context: &Junctions) {
|
||||
if context.len() < self.parents as usize {
|
||||
// Not enough context
|
||||
return
|
||||
}
|
||||
while self.parents > 0 {
|
||||
let maybe = context.at(context.len() - (self.parents as usize));
|
||||
match (self.interior.first(), maybe) {
|
||||
(Some(i), Some(j)) if i == j => {
|
||||
self.interior.take_first();
|
||||
self.parents -= 1;
|
||||
},
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<OldMultiLocation> for MultiLocation {
|
||||
type Error = ();
|
||||
fn try_from(x: OldMultiLocation) -> result::Result<Self, ()> {
|
||||
Ok(MultiLocation { parents: x.parents, interior: x.interior.try_into()? })
|
||||
}
|
||||
}
|
||||
|
||||
/// A unit struct which can be converted into a `MultiLocation` of `parents` value 1.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||
pub struct Parent;
|
||||
impl From<Parent> for MultiLocation {
|
||||
fn from(_: Parent) -> Self {
|
||||
MultiLocation { parents: 1, interior: Junctions::Here }
|
||||
}
|
||||
}
|
||||
|
||||
/// A tuple struct which can be converted into a `MultiLocation` of `parents` value 1 with the inner interior.
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||
pub struct ParentThen(pub Junctions);
|
||||
impl From<ParentThen> for MultiLocation {
|
||||
fn from(ParentThen(interior): ParentThen) -> Self {
|
||||
MultiLocation { parents: 1, interior }
|
||||
}
|
||||
}
|
||||
|
||||
/// A unit struct which can be converted into a `MultiLocation` of the inner `parents` value.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||
pub struct Ancestor(pub u8);
|
||||
impl From<Ancestor> for MultiLocation {
|
||||
fn from(Ancestor(parents): Ancestor) -> Self {
|
||||
MultiLocation { parents, interior: Junctions::Here }
|
||||
}
|
||||
}
|
||||
|
||||
/// A unit struct which can be converted into a `MultiLocation` of the inner `parents` value and the inner interior.
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||
pub struct AncestorThen<Interior>(pub u8, pub Interior);
|
||||
impl<Interior: Into<Junctions>> From<AncestorThen<Interior>> for MultiLocation {
|
||||
fn from(AncestorThen(parents, interior): AncestorThen<Interior>) -> Self {
|
||||
MultiLocation { parents, interior: interior.into() }
|
||||
}
|
||||
}
|
||||
|
||||
xcm_procedural::impl_conversion_functions_for_multilocation_v3!();
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::v3::prelude::*;
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
|
||||
#[test]
|
||||
fn conversion_works() {
|
||||
let x: MultiLocation = Parent.into();
|
||||
assert_eq!(x, MultiLocation { parents: 1, interior: Here });
|
||||
// let x: MultiLocation = (Parent,).into();
|
||||
// assert_eq!(x, MultiLocation { parents: 1, interior: Here });
|
||||
// let x: MultiLocation = (Parent, Parent).into();
|
||||
// assert_eq!(x, MultiLocation { parents: 2, interior: Here });
|
||||
let x: MultiLocation = (Parent, Parent, OnlyChild).into();
|
||||
assert_eq!(x, MultiLocation { parents: 2, interior: OnlyChild.into() });
|
||||
let x: MultiLocation = OnlyChild.into();
|
||||
assert_eq!(x, MultiLocation { parents: 0, interior: OnlyChild.into() });
|
||||
let x: MultiLocation = (OnlyChild,).into();
|
||||
assert_eq!(x, MultiLocation { parents: 0, interior: OnlyChild.into() });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simplify_basic_works() {
|
||||
let mut location: MultiLocation =
|
||||
(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
|
||||
let context = X2(Parachain(1000), PalletInstance(42));
|
||||
let expected = GeneralIndex(69).into();
|
||||
location.simplify(&context);
|
||||
assert_eq!(location, expected);
|
||||
|
||||
let mut location: MultiLocation = (Parent, PalletInstance(42), GeneralIndex(69)).into();
|
||||
let context = X1(PalletInstance(42));
|
||||
let expected = GeneralIndex(69).into();
|
||||
location.simplify(&context);
|
||||
assert_eq!(location, expected);
|
||||
|
||||
let mut location: MultiLocation = (Parent, PalletInstance(42), GeneralIndex(69)).into();
|
||||
let context = X2(Parachain(1000), PalletInstance(42));
|
||||
let expected = GeneralIndex(69).into();
|
||||
location.simplify(&context);
|
||||
assert_eq!(location, expected);
|
||||
|
||||
let mut location: MultiLocation =
|
||||
(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
|
||||
let context = X3(OnlyChild, Parachain(1000), PalletInstance(42));
|
||||
let expected = GeneralIndex(69).into();
|
||||
location.simplify(&context);
|
||||
assert_eq!(location, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simplify_incompatible_location_fails() {
|
||||
let mut location: MultiLocation =
|
||||
(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
|
||||
let context = X3(Parachain(1000), PalletInstance(42), GeneralIndex(42));
|
||||
let expected =
|
||||
(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
|
||||
location.simplify(&context);
|
||||
assert_eq!(location, expected);
|
||||
|
||||
let mut location: MultiLocation =
|
||||
(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
|
||||
let context = X1(Parachain(1000));
|
||||
let expected =
|
||||
(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
|
||||
location.simplify(&context);
|
||||
assert_eq!(location, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reanchor_works() {
|
||||
let mut id: MultiLocation = (Parent, Parachain(1000), GeneralIndex(42)).into();
|
||||
let context = Parachain(2000).into();
|
||||
let target = (Parent, Parachain(1000)).into();
|
||||
let expected = GeneralIndex(42).into();
|
||||
id.reanchor(&target, context).unwrap();
|
||||
assert_eq!(id, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_and_decode_works() {
|
||||
let m = MultiLocation {
|
||||
parents: 1,
|
||||
interior: X2(Parachain(42), AccountIndex64 { network: None, index: 23 }),
|
||||
};
|
||||
let encoded = m.encode();
|
||||
assert_eq!(encoded, [1, 2, 0, 168, 2, 0, 92].to_vec());
|
||||
let decoded = MultiLocation::decode(&mut &encoded[..]);
|
||||
assert_eq!(decoded, Ok(m));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_and_split_works() {
|
||||
let m = MultiLocation {
|
||||
parents: 1,
|
||||
interior: X2(Parachain(42), AccountIndex64 { network: None, index: 23 }),
|
||||
};
|
||||
assert_eq!(m.match_and_split(&MultiLocation { parents: 1, interior: Here }), None);
|
||||
assert_eq!(
|
||||
m.match_and_split(&MultiLocation { parents: 1, interior: X1(Parachain(42)) }),
|
||||
Some(&AccountIndex64 { network: None, index: 23 })
|
||||
);
|
||||
assert_eq!(m.match_and_split(&m), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn append_with_works() {
|
||||
let acc = AccountIndex64 { network: None, index: 23 };
|
||||
let mut m = MultiLocation { parents: 1, interior: X1(Parachain(42)) };
|
||||
assert_eq!(m.append_with(X2(PalletInstance(3), acc.clone())), Ok(()));
|
||||
assert_eq!(
|
||||
m,
|
||||
MultiLocation {
|
||||
parents: 1,
|
||||
interior: X3(Parachain(42), PalletInstance(3), acc.clone())
|
||||
}
|
||||
);
|
||||
|
||||
// cannot append to create overly long multilocation
|
||||
let acc = AccountIndex64 { network: None, index: 23 };
|
||||
let m = MultiLocation {
|
||||
parents: 254,
|
||||
interior: X5(Parachain(42), OnlyChild, OnlyChild, OnlyChild, OnlyChild),
|
||||
};
|
||||
let suffix: MultiLocation = (PalletInstance(3), acc.clone(), OnlyChild, OnlyChild).into();
|
||||
assert_eq!(m.clone().append_with(suffix.clone()), Err(suffix));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn prepend_with_works() {
|
||||
let mut m = MultiLocation {
|
||||
parents: 1,
|
||||
interior: X2(Parachain(42), AccountIndex64 { network: None, index: 23 }),
|
||||
};
|
||||
assert_eq!(m.prepend_with(MultiLocation { parents: 1, interior: X1(OnlyChild) }), Ok(()));
|
||||
assert_eq!(
|
||||
m,
|
||||
MultiLocation {
|
||||
parents: 1,
|
||||
interior: X2(Parachain(42), AccountIndex64 { network: None, index: 23 })
|
||||
}
|
||||
);
|
||||
|
||||
// cannot prepend to create overly long multilocation
|
||||
let mut m = MultiLocation { parents: 254, interior: X1(Parachain(42)) };
|
||||
let prefix = MultiLocation { parents: 2, interior: Here };
|
||||
assert_eq!(m.prepend_with(prefix.clone()), Err(prefix));
|
||||
|
||||
let prefix = MultiLocation { parents: 1, interior: Here };
|
||||
assert_eq!(m.prepend_with(prefix), Ok(()));
|
||||
assert_eq!(m, MultiLocation { parents: 255, interior: X1(Parachain(42)) });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn double_ended_ref_iteration_works() {
|
||||
let m = X3(Parachain(1000), Parachain(3), PalletInstance(5));
|
||||
let mut iter = m.iter();
|
||||
|
||||
let first = iter.next().unwrap();
|
||||
assert_eq!(first, &Parachain(1000));
|
||||
let third = iter.next_back().unwrap();
|
||||
assert_eq!(third, &PalletInstance(5));
|
||||
let second = iter.next_back().unwrap();
|
||||
assert_eq!(iter.next(), None);
|
||||
assert_eq!(iter.next_back(), None);
|
||||
assert_eq!(second, &Parachain(3));
|
||||
|
||||
let res = Here
|
||||
.pushed_with(first.clone())
|
||||
.unwrap()
|
||||
.pushed_with(second.clone())
|
||||
.unwrap()
|
||||
.pushed_with(third.clone())
|
||||
.unwrap();
|
||||
assert_eq!(m, res);
|
||||
|
||||
// make sure there's no funny business with the 0 indexing
|
||||
let m = Here;
|
||||
let mut iter = m.iter();
|
||||
|
||||
assert_eq!(iter.next(), None);
|
||||
assert_eq!(iter.next_back(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn conversion_from_other_types_works() {
|
||||
use crate::v2;
|
||||
use core::convert::TryInto;
|
||||
|
||||
fn takes_multilocation<Arg: Into<MultiLocation>>(_arg: Arg) {}
|
||||
|
||||
takes_multilocation(Parent);
|
||||
takes_multilocation(Here);
|
||||
takes_multilocation(X1(Parachain(42)));
|
||||
takes_multilocation((Ancestor(255), PalletInstance(8)));
|
||||
takes_multilocation((Ancestor(5), Parachain(1), PalletInstance(3)));
|
||||
takes_multilocation((Ancestor(2), Here));
|
||||
takes_multilocation(AncestorThen(
|
||||
3,
|
||||
X2(Parachain(43), AccountIndex64 { network: None, index: 155 }),
|
||||
));
|
||||
takes_multilocation((Parent, AccountId32 { network: None, id: [0; 32] }));
|
||||
takes_multilocation((Parent, Here));
|
||||
takes_multilocation(ParentThen(X1(Parachain(75))));
|
||||
takes_multilocation([Parachain(100), PalletInstance(3)]);
|
||||
|
||||
assert_eq!(
|
||||
v2::MultiLocation::from(v2::Junctions::Here).try_into(),
|
||||
Ok(MultiLocation::here())
|
||||
);
|
||||
assert_eq!(v2::MultiLocation::from(v2::Parent).try_into(), Ok(MultiLocation::parent()));
|
||||
assert_eq!(
|
||||
v2::MultiLocation::from((v2::Parent, v2::Parent, v2::Junction::GeneralIndex(42u128),))
|
||||
.try_into(),
|
||||
Ok(MultiLocation { parents: 2, interior: X1(GeneralIndex(42u128)) }),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,541 @@
|
||||
// Copyright 2020 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Cumulus.
|
||||
|
||||
// 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 Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Cross-Consensus Message format data structures.
|
||||
|
||||
use crate::v2::Error as OldError;
|
||||
use core::result;
|
||||
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
pub use sp_weights::Weight;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Error codes used in XCM. The first errors codes have explicit indices and are part of the XCM
|
||||
/// format. Those trailing are merely part of the XCM implementation; there is no expectation that
|
||||
/// they will retain the same index over time.
|
||||
#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)]
|
||||
pub enum Error {
|
||||
// Errors that happen due to instructions being executed. These alone are defined in the
|
||||
// XCM specification.
|
||||
/// An arithmetic overflow happened.
|
||||
#[codec(index = 0)]
|
||||
Overflow,
|
||||
/// The instruction is intentionally unsupported.
|
||||
#[codec(index = 1)]
|
||||
Unimplemented,
|
||||
/// Origin Register does not contain a value value for a reserve transfer notification.
|
||||
#[codec(index = 2)]
|
||||
UntrustedReserveLocation,
|
||||
/// Origin Register does not contain a value value for a teleport notification.
|
||||
#[codec(index = 3)]
|
||||
UntrustedTeleportLocation,
|
||||
/// `MultiLocation` value too large to descend further.
|
||||
#[codec(index = 4)]
|
||||
LocationFull,
|
||||
/// `MultiLocation` value ascend more parents than known ancestors of local location.
|
||||
#[codec(index = 5)]
|
||||
LocationNotInvertible,
|
||||
/// The Origin Register does not contain a valid value for instruction.
|
||||
#[codec(index = 6)]
|
||||
BadOrigin,
|
||||
/// The location parameter is not a valid value for the instruction.
|
||||
#[codec(index = 7)]
|
||||
InvalidLocation,
|
||||
/// The given asset is not handled.
|
||||
#[codec(index = 8)]
|
||||
AssetNotFound,
|
||||
/// An asset transaction (like withdraw or deposit) failed (typically due to type conversions).
|
||||
#[codec(index = 9)]
|
||||
FailedToTransactAsset(#[codec(skip)] &'static str),
|
||||
/// An asset cannot be withdrawn, potentially due to lack of ownership, availability or rights.
|
||||
#[codec(index = 10)]
|
||||
NotWithdrawable,
|
||||
/// An asset cannot be deposited under the ownership of a particular location.
|
||||
#[codec(index = 11)]
|
||||
LocationCannotHold,
|
||||
/// Attempt to send a message greater than the maximum supported by the transport protocol.
|
||||
#[codec(index = 12)]
|
||||
ExceedsMaxMessageSize,
|
||||
/// The given message cannot be translated into a format supported by the destination.
|
||||
#[codec(index = 13)]
|
||||
DestinationUnsupported,
|
||||
/// Destination is routable, but there is some issue with the transport mechanism.
|
||||
#[codec(index = 14)]
|
||||
Transport(#[codec(skip)] &'static str),
|
||||
/// Destination is known to be unroutable.
|
||||
#[codec(index = 15)]
|
||||
Unroutable,
|
||||
/// Used by `ClaimAsset` when the given claim could not be recognized/found.
|
||||
#[codec(index = 16)]
|
||||
UnknownClaim,
|
||||
/// Used by `Transact` when the functor cannot be decoded.
|
||||
#[codec(index = 17)]
|
||||
FailedToDecode,
|
||||
/// Used by `Transact` to indicate that the given weight limit could be breached by the functor.
|
||||
#[codec(index = 18)]
|
||||
MaxWeightInvalid,
|
||||
/// Used by `BuyExecution` when the Holding Register does not contain payable fees.
|
||||
#[codec(index = 19)]
|
||||
NotHoldingFees,
|
||||
/// Used by `BuyExecution` when the fees declared to purchase weight are insufficient.
|
||||
#[codec(index = 20)]
|
||||
TooExpensive,
|
||||
/// Used by the `Trap` instruction to force an error intentionally. Its code is included.
|
||||
#[codec(index = 21)]
|
||||
Trap(u64),
|
||||
/// Used by `ExpectAsset`, `ExpectError` and `ExpectOrigin` when the expectation was not true.
|
||||
#[codec(index = 22)]
|
||||
ExpectationFalse,
|
||||
/// The provided pallet index was not found.
|
||||
#[codec(index = 23)]
|
||||
PalletNotFound,
|
||||
/// The given pallet's name is different to that expected.
|
||||
#[codec(index = 24)]
|
||||
NameMismatch,
|
||||
/// The given pallet's version has an incompatible version to that expected.
|
||||
#[codec(index = 25)]
|
||||
VersionIncompatible,
|
||||
/// The given operation would lead to an overflow of the Holding Register.
|
||||
#[codec(index = 26)]
|
||||
HoldingWouldOverflow,
|
||||
/// The message was unable to be exported.
|
||||
#[codec(index = 27)]
|
||||
ExportError,
|
||||
/// `MultiLocation` value failed to be reanchored.
|
||||
#[codec(index = 28)]
|
||||
ReanchorFailed,
|
||||
/// No deal is possible under the given constraints.
|
||||
#[codec(index = 29)]
|
||||
NoDeal,
|
||||
/// Fees were required which the origin could not pay.
|
||||
#[codec(index = 30)]
|
||||
FeesNotMet,
|
||||
/// Some other error with locking.
|
||||
#[codec(index = 31)]
|
||||
LockError,
|
||||
/// The state was not in a condition where the operation was valid to make.
|
||||
#[codec(index = 32)]
|
||||
NoPermission,
|
||||
/// The universal location of the local consensus is improper.
|
||||
#[codec(index = 33)]
|
||||
Unanchored,
|
||||
/// An asset cannot be deposited, probably because (too much of) it already exists.
|
||||
#[codec(index = 34)]
|
||||
NotDepositable,
|
||||
|
||||
// Errors that happen prior to instructions being executed. These fall outside of the XCM spec.
|
||||
/// XCM version not able to be handled.
|
||||
UnhandledXcmVersion,
|
||||
/// Execution of the XCM would potentially result in a greater weight used than weight limit.
|
||||
WeightLimitReached(Weight),
|
||||
/// The XCM did not pass the barrier condition for execution.
|
||||
///
|
||||
/// The barrier condition differs on different chains and in different circumstances, but
|
||||
/// generally it means that the conditions surrounding the message were not such that the chain
|
||||
/// considers the message worth spending time executing. Since most chains lift the barrier to
|
||||
/// execution on appropriate payment, presentation of an NFT voucher, or based on the message
|
||||
/// origin, it means that none of those were the case.
|
||||
Barrier,
|
||||
/// The weight of an XCM message is not computable ahead of execution.
|
||||
WeightNotComputable,
|
||||
/// Recursion stack limit reached
|
||||
ExceedsStackLimit,
|
||||
}
|
||||
|
||||
impl MaxEncodedLen for Error {
|
||||
fn max_encoded_len() -> usize {
|
||||
// TODO: max_encoded_len doesn't quite work here as it tries to take notice of the fields
|
||||
// marked `codec(skip)`. We can hard-code it with the right answer for now.
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<OldError> for Error {
|
||||
type Error = ();
|
||||
fn try_from(old_error: OldError) -> result::Result<Error, ()> {
|
||||
use OldError::*;
|
||||
Ok(match old_error {
|
||||
Overflow => Self::Overflow,
|
||||
Unimplemented => Self::Unimplemented,
|
||||
UntrustedReserveLocation => Self::UntrustedReserveLocation,
|
||||
UntrustedTeleportLocation => Self::UntrustedTeleportLocation,
|
||||
MultiLocationFull => Self::LocationFull,
|
||||
MultiLocationNotInvertible => Self::LocationNotInvertible,
|
||||
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::NotApplicable | SendError::Unroutable | SendError::MissingArgument =>
|
||||
Error::Unroutable,
|
||||
SendError::Transport(s) => Error::Transport(s),
|
||||
SendError::DestinationUnsupported => Error::DestinationUnsupported,
|
||||
SendError::ExceedsMaxMessageSize => Error::ExceedsMaxMessageSize,
|
||||
SendError::Fees => Error::FeesNotMet,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type Result = result::Result<(), Error>;
|
||||
|
||||
/// Outcome of an XCM execution.
|
||||
#[derive(Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)]
|
||||
pub enum Outcome {
|
||||
/// Execution completed successfully; given weight was used.
|
||||
Complete(Weight),
|
||||
/// Execution started, but did not complete successfully due to the given error; given weight was used.
|
||||
Incomplete(Weight, Error),
|
||||
/// Execution did not start due to the given error.
|
||||
Error(Error),
|
||||
}
|
||||
|
||||
impl Outcome {
|
||||
pub fn ensure_complete(self) -> Result {
|
||||
match self {
|
||||
Outcome::Complete(_) => Ok(()),
|
||||
Outcome::Incomplete(_, e) => Err(e),
|
||||
Outcome::Error(e) => Err(e),
|
||||
}
|
||||
}
|
||||
pub fn ensure_execution(self) -> result::Result<Weight, Error> {
|
||||
match self {
|
||||
Outcome::Complete(w) => Ok(w),
|
||||
Outcome::Incomplete(w, _) => Ok(w),
|
||||
Outcome::Error(e) => Err(e),
|
||||
}
|
||||
}
|
||||
/// How much weight was used by the XCM execution attempt.
|
||||
pub fn weight_used(&self) -> Weight {
|
||||
match self {
|
||||
Outcome::Complete(w) => *w,
|
||||
Outcome::Incomplete(w, _) => *w,
|
||||
Outcome::Error(_) => Weight::zero(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PreparedMessage {
|
||||
fn weight_of(&self) -> Weight;
|
||||
}
|
||||
|
||||
/// Type of XCM message executor.
|
||||
pub trait ExecuteXcm<Call> {
|
||||
type Prepared: PreparedMessage;
|
||||
fn prepare(message: Xcm<Call>) -> result::Result<Self::Prepared, Xcm<Call>>;
|
||||
fn execute(
|
||||
origin: impl Into<MultiLocation>,
|
||||
pre: Self::Prepared,
|
||||
hash: XcmHash,
|
||||
weight_credit: Weight,
|
||||
) -> Outcome;
|
||||
|
||||
/// Execute some XCM `message` with the message `hash` from `origin` using no more than `weight_limit` weight.
|
||||
/// The weight limit is a basic hard-limit and the implementation may place further restrictions or requirements
|
||||
/// on weight and other aspects.
|
||||
fn execute_xcm(
|
||||
origin: impl Into<MultiLocation>,
|
||||
message: Xcm<Call>,
|
||||
hash: XcmHash,
|
||||
weight_limit: Weight,
|
||||
) -> Outcome {
|
||||
let origin = origin.into();
|
||||
log::debug!(
|
||||
target: "xcm::execute_xcm",
|
||||
"origin: {:?}, message: {:?}, weight_limit: {:?}",
|
||||
origin,
|
||||
message,
|
||||
weight_limit,
|
||||
);
|
||||
Self::execute_xcm_in_credit(origin, message, hash, weight_limit, Weight::zero())
|
||||
}
|
||||
|
||||
/// Execute some XCM `message` with the message `hash` from `origin` using no more than `weight_limit` weight.
|
||||
///
|
||||
/// Some amount of `weight_credit` may be provided which, depending on the implementation, may allow
|
||||
/// execution without associated payment.
|
||||
fn execute_xcm_in_credit(
|
||||
origin: impl Into<MultiLocation>,
|
||||
message: Xcm<Call>,
|
||||
hash: XcmHash,
|
||||
weight_limit: Weight,
|
||||
weight_credit: Weight,
|
||||
) -> Outcome {
|
||||
let pre = match Self::prepare(message) {
|
||||
Ok(x) => x,
|
||||
Err(_) => return Outcome::Error(Error::WeightNotComputable),
|
||||
};
|
||||
let xcm_weight = pre.weight_of();
|
||||
if xcm_weight.any_gt(weight_limit) {
|
||||
return Outcome::Error(Error::WeightLimitReached(xcm_weight))
|
||||
}
|
||||
Self::execute(origin, pre, hash, weight_credit)
|
||||
}
|
||||
|
||||
/// Deduct some `fees` to the sovereign account of the given `location` and place them as per
|
||||
/// the convention for fees.
|
||||
fn charge_fees(location: impl Into<MultiLocation>, fees: MultiAssets) -> Result;
|
||||
}
|
||||
|
||||
pub enum Weightless {}
|
||||
impl PreparedMessage for Weightless {
|
||||
fn weight_of(&self) -> Weight {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> ExecuteXcm<C> for () {
|
||||
type Prepared = Weightless;
|
||||
fn prepare(message: Xcm<C>) -> result::Result<Self::Prepared, Xcm<C>> {
|
||||
Err(message)
|
||||
}
|
||||
fn execute(_: impl Into<MultiLocation>, _: Self::Prepared, _: XcmHash, _: Weight) -> Outcome {
|
||||
unreachable!()
|
||||
}
|
||||
fn charge_fees(_location: impl Into<MultiLocation>, _fees: MultiAssets) -> Result {
|
||||
Err(Error::Unimplemented)
|
||||
}
|
||||
}
|
||||
|
||||
/// Error result value when attempting to send an XCM message.
|
||||
#[derive(Clone, Encode, Decode, Eq, PartialEq, Debug, scale_info::TypeInfo)]
|
||||
pub enum SendError {
|
||||
/// The message and destination combination was not recognized as being reachable.
|
||||
///
|
||||
/// This is not considered fatal: if there are alternative transport routes available, then
|
||||
/// they may be attempted.
|
||||
NotApplicable,
|
||||
/// 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.
|
||||
Transport(#[codec(skip)] &'static str),
|
||||
/// Destination is known to be unroutable. This is considered fatal.
|
||||
Unroutable,
|
||||
/// The given message cannot be translated into a format that the destination can be expected
|
||||
/// to interpret.
|
||||
DestinationUnsupported,
|
||||
/// Message could not be sent due to its size exceeding the maximum allowed by the transport
|
||||
/// layer.
|
||||
ExceedsMaxMessageSize,
|
||||
/// A needed argument is `None` when it should be `Some`.
|
||||
MissingArgument,
|
||||
/// Fees needed to be paid in order to send the message and they were unavailable.
|
||||
Fees,
|
||||
}
|
||||
|
||||
/// A hash type for identifying messages.
|
||||
pub type XcmHash = [u8; 32];
|
||||
|
||||
/// Result value when attempting to send an XCM message.
|
||||
pub type SendResult<T> = result::Result<(T, MultiAssets), SendError>;
|
||||
|
||||
pub trait Unwrappable {
|
||||
type Inner;
|
||||
fn none() -> Self;
|
||||
fn some(i: Self::Inner) -> Self;
|
||||
fn take(self) -> Option<Self::Inner>;
|
||||
}
|
||||
|
||||
impl<T> Unwrappable for Option<T> {
|
||||
type Inner = T;
|
||||
fn none() -> Self {
|
||||
None
|
||||
}
|
||||
fn some(i: Self::Inner) -> Self {
|
||||
Some(i)
|
||||
}
|
||||
fn take(self) -> Option<Self::Inner> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Utility for sending an XCM message to a given location.
|
||||
///
|
||||
/// These can be amalgamated in tuples to form sophisticated routing systems. In tuple format, each
|
||||
/// router might return `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.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use parity_scale_codec::Encode;
|
||||
/// # use xcm::v3::{prelude::*, Weight};
|
||||
/// # use xcm::VersionedXcm;
|
||||
/// # use std::convert::Infallible;
|
||||
///
|
||||
/// /// A sender that only passes the message through and does nothing.
|
||||
/// struct Sender1;
|
||||
/// impl SendXcm for Sender1 {
|
||||
/// type Ticket = Infallible;
|
||||
/// fn validate(_: &mut Option<MultiLocation>, _: &mut Option<Xcm<()>>) -> SendResult<Infallible> {
|
||||
/// Err(SendError::NotApplicable)
|
||||
/// }
|
||||
/// fn deliver(_: Infallible) -> Result<XcmHash, SendError> {
|
||||
/// unreachable!()
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// /// A sender that accepts a message that has an X2 junction, otherwise stops the routing.
|
||||
/// struct Sender2;
|
||||
/// impl SendXcm for Sender2 {
|
||||
/// type Ticket = ();
|
||||
/// fn validate(destination: &mut Option<MultiLocation>, message: &mut Option<Xcm<()>>) -> SendResult<()> {
|
||||
/// match destination.as_ref().ok_or(SendError::MissingArgument)? {
|
||||
/// MultiLocation { parents: 0, interior: X2(j1, j2) } => Ok(((), MultiAssets::new())),
|
||||
/// _ => Err(SendError::Unroutable),
|
||||
/// }
|
||||
/// }
|
||||
/// fn deliver(_: ()) -> Result<XcmHash, SendError> {
|
||||
/// Ok([0; 32])
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// /// A sender that accepts a message from a parent, passing through otherwise.
|
||||
/// struct Sender3;
|
||||
/// impl SendXcm for Sender3 {
|
||||
/// type Ticket = ();
|
||||
/// fn validate(destination: &mut Option<MultiLocation>, message: &mut Option<Xcm<()>>) -> SendResult<()> {
|
||||
/// match destination.as_ref().ok_or(SendError::MissingArgument)? {
|
||||
/// MultiLocation { parents: 1, interior: Here } => Ok(((), MultiAssets::new())),
|
||||
/// _ => Err(SendError::NotApplicable),
|
||||
/// }
|
||||
/// }
|
||||
/// fn deliver(_: ()) -> Result<XcmHash, SendError> {
|
||||
/// Ok([0; 32])
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // A call to send via XCM. We don't really care about this.
|
||||
/// # fn main() {
|
||||
/// let call: Vec<u8> = ().encode();
|
||||
/// let message = Xcm(vec![Instruction::Transact {
|
||||
/// origin_kind: OriginKind::Superuser,
|
||||
/// require_weight_at_most: Weight::zero(),
|
||||
/// call: call.into(),
|
||||
/// }]);
|
||||
/// let message_hash = message.using_encoded(sp_io::hashing::blake2_256);
|
||||
///
|
||||
/// // Sender2 will block this.
|
||||
/// assert!(send_xcm::<(Sender1, Sender2, Sender3)>(Parent.into(), message.clone()).is_err());
|
||||
///
|
||||
/// // Sender3 will catch this.
|
||||
/// assert!(send_xcm::<(Sender1, Sender3)>(Parent.into(), message.clone()).is_ok());
|
||||
/// # }
|
||||
/// ```
|
||||
pub trait SendXcm {
|
||||
/// Intermediate value which connects the two phaases of the send operation.
|
||||
type Ticket;
|
||||
|
||||
/// Check whether the given `_message` is deliverable to the given `_destination` and if so
|
||||
/// determine the cost which will be paid by this chain to do so, returning a `Validated` token
|
||||
/// which can be used to enact delivery.
|
||||
///
|
||||
/// The `destination` and `message` must be `Some` (or else an error will be returned) and they
|
||||
/// may only be consumed if the `Err` is not `NotApplicable`.
|
||||
///
|
||||
/// If it is not a destination which can be reached with this type but possibly could by others,
|
||||
/// then this *MUST* return `NotApplicable`. Any other error will cause the tuple
|
||||
/// implementation to exit early without trying other type fields.
|
||||
fn validate(
|
||||
destination: &mut Option<MultiLocation>,
|
||||
message: &mut Option<Xcm<()>>,
|
||||
) -> SendResult<Self::Ticket>;
|
||||
|
||||
/// Actually carry out the delivery operation for a previously validated message sending.
|
||||
fn deliver(ticket: Self::Ticket) -> result::Result<XcmHash, SendError>;
|
||||
}
|
||||
|
||||
#[impl_trait_for_tuples::impl_for_tuples(30)]
|
||||
impl SendXcm for Tuple {
|
||||
for_tuples! { type Ticket = (#( Option<Tuple::Ticket> ),* ); }
|
||||
|
||||
fn validate(
|
||||
destination: &mut Option<MultiLocation>,
|
||||
message: &mut Option<Xcm<()>>,
|
||||
) -> SendResult<Self::Ticket> {
|
||||
let mut maybe_cost: Option<MultiAssets> = None;
|
||||
let one_ticket: Self::Ticket = (for_tuples! { #(
|
||||
if maybe_cost.is_some() {
|
||||
None
|
||||
} else {
|
||||
match Tuple::validate(destination, message) {
|
||||
Err(SendError::NotApplicable) => None,
|
||||
Err(e) => { return Err(e) },
|
||||
Ok((v, c)) => {
|
||||
maybe_cost = Some(c);
|
||||
Some(v)
|
||||
},
|
||||
}
|
||||
}
|
||||
),* });
|
||||
if let Some(cost) = maybe_cost {
|
||||
Ok((one_ticket, cost))
|
||||
} else {
|
||||
Err(SendError::NotApplicable)
|
||||
}
|
||||
}
|
||||
|
||||
fn deliver(one_ticket: Self::Ticket) -> result::Result<XcmHash, SendError> {
|
||||
for_tuples!( #(
|
||||
if let Some(validated) = one_ticket.Tuple {
|
||||
return Tuple::deliver(validated);
|
||||
}
|
||||
)* );
|
||||
Err(SendError::Unroutable)
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience function for using a `SendXcm` implementation. Just interprets the `dest` and wraps
|
||||
/// both in `Some` before passing them as as mutable references into `T::send_xcm`.
|
||||
pub fn validate_send<T: SendXcm>(dest: MultiLocation, msg: Xcm<()>) -> SendResult<T::Ticket> {
|
||||
T::validate(&mut Some(dest), &mut Some(msg))
|
||||
}
|
||||
|
||||
/// Convenience function for using a `SendXcm` implementation. Just interprets the `dest` and wraps
|
||||
/// both in `Some` before passing them as as mutable references into `T::send_xcm`.
|
||||
///
|
||||
/// Returns either `Ok` with the price of the delivery, or `Err` with the reason why the message
|
||||
/// could not be sent.
|
||||
///
|
||||
/// Generally you'll want to validate and get the price first to ensure that the sender can pay it
|
||||
/// before actually doing the delivery.
|
||||
pub fn send_xcm<T: SendXcm>(
|
||||
dest: MultiLocation,
|
||||
msg: Xcm<()>,
|
||||
) -> result::Result<(XcmHash, MultiAssets), SendError> {
|
||||
let (ticket, price) = T::validate(&mut Some(dest), &mut Some(msg))?;
|
||||
let hash = T::deliver(ticket)?;
|
||||
Ok((hash, price))
|
||||
}
|
||||
@@ -6,6 +6,7 @@ edition.workspace = true
|
||||
version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
impl-trait-for-tuples = "0.2.1"
|
||||
parity-scale-codec = { version = "3.1.5", default-features = false, features = ["derive"] }
|
||||
scale-info = { version = "2.1.2", default-features = false, features = ["derive"] }
|
||||
xcm = { path = "..", default-features = false }
|
||||
@@ -27,6 +28,8 @@ sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
pallet-xcm = { path = "../pallet-xcm" }
|
||||
polkadot-runtime-parachains = { path = "../../runtime/parachains" }
|
||||
assert_matches = "1.5.0"
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
runtime-benchmarks = [
|
||||
@@ -44,6 +47,7 @@ std = [
|
||||
"sp-io/std",
|
||||
"sp-runtime/std",
|
||||
"frame-support/std",
|
||||
"frame-system/std",
|
||||
"polkadot-parachain/std",
|
||||
"pallet-transaction-payment/std",
|
||||
]
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
// Copyright 2022 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/>.
|
||||
|
||||
//! Adapters to work with `frame_support::traits::tokens::fungibles` through XCM.
|
||||
|
||||
use frame_support::traits::Get;
|
||||
use sp_std::{borrow::Borrow, marker::PhantomData, prelude::*, result};
|
||||
use xcm::latest::prelude::*;
|
||||
use xcm_executor::traits::{Convert, Error as MatchError, MatchesFungibles, MatchesNonFungibles};
|
||||
|
||||
/// Converter struct implementing `AssetIdConversion` converting a numeric asset ID (must be `TryFrom/TryInto<u128>`) into
|
||||
/// a `GeneralIndex` junction, prefixed by some `MultiLocation` value. The `MultiLocation` value will typically be a
|
||||
/// `PalletInstance` junction.
|
||||
pub struct AsPrefixedGeneralIndex<Prefix, AssetId, ConvertAssetId>(
|
||||
PhantomData<(Prefix, AssetId, ConvertAssetId)>,
|
||||
);
|
||||
impl<Prefix: Get<MultiLocation>, AssetId: Clone, ConvertAssetId: Convert<u128, AssetId>>
|
||||
Convert<MultiLocation, AssetId> for AsPrefixedGeneralIndex<Prefix, AssetId, ConvertAssetId>
|
||||
{
|
||||
fn convert_ref(id: impl Borrow<MultiLocation>) -> result::Result<AssetId, ()> {
|
||||
let prefix = Prefix::get();
|
||||
let id = id.borrow();
|
||||
if prefix.parent_count() != id.parent_count() ||
|
||||
prefix
|
||||
.interior()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.any(|(index, junction)| id.interior().at(index) != Some(junction))
|
||||
{
|
||||
return Err(())
|
||||
}
|
||||
match id.interior().at(prefix.interior().len()) {
|
||||
Some(Junction::GeneralIndex(id)) => ConvertAssetId::convert_ref(id),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
fn reverse_ref(what: impl Borrow<AssetId>) -> result::Result<MultiLocation, ()> {
|
||||
let mut location = Prefix::get();
|
||||
let id = ConvertAssetId::reverse_ref(what)?;
|
||||
location.push_interior(Junction::GeneralIndex(id)).map_err(|_| ())?;
|
||||
Ok(location)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ConvertedConcreteId<AssetId, Balance, ConvertAssetId, ConvertOther>(
|
||||
PhantomData<(AssetId, Balance, ConvertAssetId, ConvertOther)>,
|
||||
);
|
||||
impl<
|
||||
AssetId: Clone,
|
||||
Balance: Clone,
|
||||
ConvertAssetId: Convert<MultiLocation, AssetId>,
|
||||
ConvertBalance: Convert<u128, Balance>,
|
||||
> MatchesFungibles<AssetId, Balance>
|
||||
for ConvertedConcreteId<AssetId, Balance, ConvertAssetId, ConvertBalance>
|
||||
{
|
||||
fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), MatchError> {
|
||||
let (amount, id) = match (&a.fun, &a.id) {
|
||||
(Fungible(ref amount), Concrete(ref id)) => (amount, id),
|
||||
_ => return Err(MatchError::AssetNotFound),
|
||||
};
|
||||
let what =
|
||||
ConvertAssetId::convert_ref(id).map_err(|_| MatchError::AssetIdConversionFailed)?;
|
||||
let amount = ConvertBalance::convert_ref(amount)
|
||||
.map_err(|_| MatchError::AmountToBalanceConversionFailed)?;
|
||||
Ok((what, amount))
|
||||
}
|
||||
}
|
||||
impl<
|
||||
ClassId: Clone,
|
||||
InstanceId: Clone,
|
||||
ConvertClassId: Convert<MultiLocation, ClassId>,
|
||||
ConvertInstanceId: Convert<AssetInstance, InstanceId>,
|
||||
> MatchesNonFungibles<ClassId, InstanceId>
|
||||
for ConvertedConcreteId<ClassId, InstanceId, ConvertClassId, ConvertInstanceId>
|
||||
{
|
||||
fn matches_nonfungibles(a: &MultiAsset) -> result::Result<(ClassId, InstanceId), MatchError> {
|
||||
let (instance, class) = match (&a.fun, &a.id) {
|
||||
(NonFungible(ref instance), Concrete(ref class)) => (instance, class),
|
||||
_ => return Err(MatchError::AssetNotFound),
|
||||
};
|
||||
let what =
|
||||
ConvertClassId::convert_ref(class).map_err(|_| MatchError::AssetIdConversionFailed)?;
|
||||
let instance = ConvertInstanceId::convert_ref(instance)
|
||||
.map_err(|_| MatchError::InstanceConversionFailed)?;
|
||||
Ok((what, instance))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ConvertedAbstractId<AssetId, Balance, ConvertAssetId, ConvertOther>(
|
||||
PhantomData<(AssetId, Balance, ConvertAssetId, ConvertOther)>,
|
||||
);
|
||||
impl<
|
||||
AssetId: Clone,
|
||||
Balance: Clone,
|
||||
ConvertAssetId: Convert<[u8; 32], AssetId>,
|
||||
ConvertBalance: Convert<u128, Balance>,
|
||||
> MatchesFungibles<AssetId, Balance>
|
||||
for ConvertedAbstractId<AssetId, Balance, ConvertAssetId, ConvertBalance>
|
||||
{
|
||||
fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), MatchError> {
|
||||
let (amount, id) = match (&a.fun, &a.id) {
|
||||
(Fungible(ref amount), Abstract(ref id)) => (amount, id),
|
||||
_ => return Err(MatchError::AssetNotFound),
|
||||
};
|
||||
let what =
|
||||
ConvertAssetId::convert_ref(id).map_err(|_| MatchError::AssetIdConversionFailed)?;
|
||||
let amount = ConvertBalance::convert_ref(amount)
|
||||
.map_err(|_| MatchError::AmountToBalanceConversionFailed)?;
|
||||
Ok((what, amount))
|
||||
}
|
||||
}
|
||||
impl<
|
||||
ClassId: Clone,
|
||||
InstanceId: Clone,
|
||||
ConvertClassId: Convert<[u8; 32], ClassId>,
|
||||
ConvertInstanceId: Convert<AssetInstance, InstanceId>,
|
||||
> MatchesNonFungibles<ClassId, InstanceId>
|
||||
for ConvertedAbstractId<ClassId, InstanceId, ConvertClassId, ConvertInstanceId>
|
||||
{
|
||||
fn matches_nonfungibles(a: &MultiAsset) -> result::Result<(ClassId, InstanceId), MatchError> {
|
||||
let (instance, class) = match (&a.fun, &a.id) {
|
||||
(NonFungible(ref instance), Abstract(ref class)) => (instance, class),
|
||||
_ => return Err(MatchError::AssetNotFound),
|
||||
};
|
||||
let what =
|
||||
ConvertClassId::convert_ref(class).map_err(|_| MatchError::AssetIdConversionFailed)?;
|
||||
let instance = ConvertInstanceId::convert_ref(instance)
|
||||
.map_err(|_| MatchError::InstanceConversionFailed)?;
|
||||
Ok((what, instance))
|
||||
}
|
||||
}
|
||||
|
||||
#[deprecated = "Use `ConvertedConcreteId` instead"]
|
||||
pub type ConvertedConcreteAssetId<A, B, C, O> = ConvertedConcreteId<A, B, C, O>;
|
||||
#[deprecated = "Use `ConvertedAbstractId` instead"]
|
||||
pub type ConvertedAbstractAssetId<A, B, C, O> = ConvertedAbstractId<A, B, C, O>;
|
||||
@@ -16,11 +16,18 @@
|
||||
|
||||
//! Various implementations for `ShouldExecute`.
|
||||
|
||||
use frame_support::{ensure, traits::Contains};
|
||||
use frame_support::{
|
||||
ensure,
|
||||
traits::{Contains, Get},
|
||||
};
|
||||
use polkadot_parachain::primitives::IsSystem;
|
||||
use sp_std::{marker::PhantomData, result::Result};
|
||||
use xcm::latest::{
|
||||
Instruction::*, Junction, Junctions, MultiLocation, Weight, WeightLimit::*, Xcm,
|
||||
Instruction::{self, *},
|
||||
InteriorMultiLocation, Junction, Junctions,
|
||||
Junctions::X1,
|
||||
MultiLocation, Weight,
|
||||
WeightLimit::*,
|
||||
};
|
||||
use xcm_executor::traits::{OnResponse, ShouldExecute};
|
||||
|
||||
@@ -33,16 +40,16 @@ pub struct TakeWeightCredit;
|
||||
impl ShouldExecute for TakeWeightCredit {
|
||||
fn should_execute<RuntimeCall>(
|
||||
_origin: &MultiLocation,
|
||||
_message: &mut Xcm<RuntimeCall>,
|
||||
_instructions: &mut [Instruction<RuntimeCall>],
|
||||
max_weight: Weight,
|
||||
weight_credit: &mut Weight,
|
||||
) -> Result<(), ()> {
|
||||
log::trace!(
|
||||
target: "xcm::barriers",
|
||||
"TakeWeightCredit origin: {:?}, message: {:?}, max_weight: {:?}, weight_credit: {:?}",
|
||||
_origin, _message, max_weight, weight_credit,
|
||||
"TakeWeightCredit origin: {:?}, instructions: {:?}, max_weight: {:?}, weight_credit: {:?}",
|
||||
_origin, _instructions, max_weight, weight_credit,
|
||||
);
|
||||
*weight_credit = weight_credit.checked_sub(max_weight).ok_or(())?;
|
||||
*weight_credit = weight_credit.checked_sub(&max_weight).ok_or(())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -56,17 +63,21 @@ pub struct AllowTopLevelPaidExecutionFrom<T>(PhantomData<T>);
|
||||
impl<T: Contains<MultiLocation>> ShouldExecute for AllowTopLevelPaidExecutionFrom<T> {
|
||||
fn should_execute<RuntimeCall>(
|
||||
origin: &MultiLocation,
|
||||
message: &mut Xcm<RuntimeCall>,
|
||||
instructions: &mut [Instruction<RuntimeCall>],
|
||||
max_weight: Weight,
|
||||
_weight_credit: &mut Weight,
|
||||
) -> Result<(), ()> {
|
||||
log::trace!(
|
||||
target: "xcm::barriers",
|
||||
"AllowTopLevelPaidExecutionFrom origin: {:?}, message: {:?}, max_weight: {:?}, weight_credit: {:?}",
|
||||
origin, message, max_weight, _weight_credit,
|
||||
"AllowTopLevelPaidExecutionFrom origin: {:?}, instructions: {:?}, max_weight: {:?}, weight_credit: {:?}",
|
||||
origin, instructions, max_weight, _weight_credit,
|
||||
);
|
||||
|
||||
ensure!(T::contains(origin), ());
|
||||
let mut iter = message.0.iter_mut();
|
||||
// We will read up to 5 instructions. This allows up to 3 `ClearOrigin` instructions. We
|
||||
// allow for more than one since anything beyond the first is a no-op and it's conceivable
|
||||
// that composition of operations might result in more than one being appended.
|
||||
let mut iter = instructions.iter_mut().take(5);
|
||||
let i = iter.next().ok_or(())?;
|
||||
match i {
|
||||
ReceiveTeleportedAsset(..) |
|
||||
@@ -80,8 +91,10 @@ impl<T: Contains<MultiLocation>> ShouldExecute for AllowTopLevelPaidExecutionFro
|
||||
i = iter.next().ok_or(())?;
|
||||
}
|
||||
match i {
|
||||
BuyExecution { weight_limit: Limited(ref mut weight), .. } if *weight >= max_weight => {
|
||||
*weight = max_weight;
|
||||
BuyExecution { weight_limit: Limited(ref mut weight), .. }
|
||||
if weight.all_gte(max_weight) =>
|
||||
{
|
||||
*weight = weight.max(max_weight);
|
||||
Ok(())
|
||||
},
|
||||
BuyExecution { ref mut weight_limit, .. } if weight_limit == &Unlimited => {
|
||||
@@ -93,26 +106,150 @@ impl<T: Contains<MultiLocation>> ShouldExecute for AllowTopLevelPaidExecutionFro
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows execution from any origin that is contained in `T` (i.e. `T::Contains(origin)`) without any payments.
|
||||
/// Use only for executions from trusted origin groups.
|
||||
/// A derivative barrier, which scans the first `MaxPrefixes` instructions for origin-alterers and
|
||||
/// then evaluates `should_execute` of the `InnerBarrier` based on the remaining instructions and
|
||||
/// the newly computed origin.
|
||||
///
|
||||
/// This effectively allows for the possibility of distinguishing an origin which is acting as a
|
||||
/// router for its derivative locations (or as a bridge for a remote location) and an origin which
|
||||
/// is actually trying to send a message for itself. In the former case, the message will be
|
||||
/// prefixed with origin-mutating instructions.
|
||||
///
|
||||
/// Any barriers which should be interpreted based on the computed origin rather than the original
|
||||
/// message origin should be subject to this. This is the case for most barriers since the
|
||||
/// effective origin is generally more important than the routing origin. Any other barriers, and
|
||||
/// especially those which should be interpreted only the routing origin should not be subject to
|
||||
/// this.
|
||||
///
|
||||
/// E.g.
|
||||
/// ```nocompile
|
||||
/// type MyBarrier = (
|
||||
/// TakeWeightCredit,
|
||||
/// AllowTopLevelPaidExecutionFrom<DirectCustomerLocations>,
|
||||
/// WithComputedOrigin<(
|
||||
/// AllowTopLevelPaidExecutionFrom<DerivativeCustomerLocations>,
|
||||
/// AllowUnpaidExecutionFrom<ParentLocation>,
|
||||
/// AllowSubscriptionsFrom<AllowedSubscribers>,
|
||||
/// AllowKnownQueryResponses<TheResponseHandler>,
|
||||
/// )>,
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// In the above example, `AllowUnpaidExecutionFrom` appears once underneath
|
||||
/// `WithComputedOrigin`. This is in order to distinguish between messages which are notionally
|
||||
/// from a derivative location of `ParentLocation` but that just happened to be sent via
|
||||
/// `ParentLocaction` rather than messages that were sent by the parent.
|
||||
///
|
||||
/// Similarly `AllowTopLevelPaidExecutionFrom` appears twice: once inside of `WithComputedOrigin`
|
||||
/// where we provide the list of origins which are derivative origins, and then secondly outside
|
||||
/// of `WithComputedOrigin` where we provide the list of locations which are direct origins. It's
|
||||
/// reasonable for these lists to be merged into one and that used both inside and out.
|
||||
///
|
||||
/// Finally, we see `AllowSubscriptionsFrom` and `AllowKnownQueryResponses` are both inside of
|
||||
/// `WithComputedOrigin`. This means that if a message begins with origin-mutating instructions,
|
||||
/// then it must be the finally computed origin which we accept subscriptions or expect a query
|
||||
/// response from. For example, even if an origin appeared in the `AllowedSubscribers` list, we
|
||||
/// would ignore this rule if it began with origin mutators and they changed the origin to something
|
||||
/// which was not on the list.
|
||||
pub struct WithComputedOrigin<InnerBarrier, LocalUniversal, MaxPrefixes>(
|
||||
PhantomData<(InnerBarrier, LocalUniversal, MaxPrefixes)>,
|
||||
);
|
||||
impl<
|
||||
InnerBarrier: ShouldExecute,
|
||||
LocalUniversal: Get<InteriorMultiLocation>,
|
||||
MaxPrefixes: Get<u32>,
|
||||
> ShouldExecute for WithComputedOrigin<InnerBarrier, LocalUniversal, MaxPrefixes>
|
||||
{
|
||||
fn should_execute<Call>(
|
||||
origin: &MultiLocation,
|
||||
instructions: &mut [Instruction<Call>],
|
||||
max_weight: Weight,
|
||||
weight_credit: &mut Weight,
|
||||
) -> Result<(), ()> {
|
||||
log::trace!(
|
||||
target: "xcm::barriers",
|
||||
"WithComputedOrigin origin: {:?}, instructions: {:?}, max_weight: {:?}, weight_credit: {:?}",
|
||||
origin, instructions, max_weight, weight_credit,
|
||||
);
|
||||
let mut actual_origin = *origin;
|
||||
let mut skipped = 0;
|
||||
// NOTE: We do not check the validity of `UniversalOrigin` here, meaning that a malicious
|
||||
// origin could place a `UniversalOrigin` in order to spoof some location which gets free
|
||||
// execution. This technical could get it past the barrier condition, but the execution
|
||||
// would instantly fail since the first instruction would cause an error with the
|
||||
// invalid UniversalOrigin.
|
||||
while skipped < MaxPrefixes::get() as usize {
|
||||
match instructions.get(skipped) {
|
||||
Some(UniversalOrigin(new_global)) => {
|
||||
// Note the origin is *relative to local consensus*! So we need to escape local
|
||||
// consensus with the `parents` before diving in into the `universal_location`.
|
||||
actual_origin = X1(*new_global).relative_to(&LocalUniversal::get());
|
||||
},
|
||||
Some(DescendOrigin(j)) => {
|
||||
actual_origin.append_with(*j).map_err(|_| ())?;
|
||||
},
|
||||
_ => break,
|
||||
}
|
||||
skipped += 1;
|
||||
}
|
||||
InnerBarrier::should_execute(
|
||||
&actual_origin,
|
||||
&mut instructions[skipped..],
|
||||
max_weight,
|
||||
weight_credit,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows execution from any origin that is contained in `T` (i.e. `T::Contains(origin)`).
|
||||
///
|
||||
/// Use only for executions from completely trusted origins, from which no unpermissioned messages
|
||||
/// can be sent.
|
||||
pub struct AllowUnpaidExecutionFrom<T>(PhantomData<T>);
|
||||
impl<T: Contains<MultiLocation>> ShouldExecute for AllowUnpaidExecutionFrom<T> {
|
||||
fn should_execute<RuntimeCall>(
|
||||
origin: &MultiLocation,
|
||||
_message: &mut Xcm<RuntimeCall>,
|
||||
instructions: &mut [Instruction<RuntimeCall>],
|
||||
_max_weight: Weight,
|
||||
_weight_credit: &mut Weight,
|
||||
) -> Result<(), ()> {
|
||||
log::trace!(
|
||||
target: "xcm::barriers",
|
||||
"AllowUnpaidExecutionFrom origin: {:?}, message: {:?}, max_weight: {:?}, weight_credit: {:?}",
|
||||
origin, _message, _max_weight, _weight_credit,
|
||||
"AllowUnpaidExecutionFrom origin: {:?}, instructions: {:?}, max_weight: {:?}, weight_credit: {:?}",
|
||||
origin, instructions, _max_weight, _weight_credit,
|
||||
);
|
||||
ensure!(T::contains(origin), ());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows execution from any origin that is contained in `T` (i.e. `T::Contains(origin)`) if the
|
||||
/// message begins with the instruction `UnpaidExecution`.
|
||||
///
|
||||
/// Use only for executions from trusted origin groups.
|
||||
pub struct AllowExplicitUnpaidExecutionFrom<T>(PhantomData<T>);
|
||||
impl<T: Contains<MultiLocation>> ShouldExecute for AllowExplicitUnpaidExecutionFrom<T> {
|
||||
fn should_execute<Call>(
|
||||
origin: &MultiLocation,
|
||||
instructions: &mut [Instruction<Call>],
|
||||
max_weight: Weight,
|
||||
_weight_credit: &mut Weight,
|
||||
) -> Result<(), ()> {
|
||||
log::trace!(
|
||||
target: "xcm::barriers",
|
||||
"AllowExplicitUnpaidExecutionFrom origin: {:?}, instructions: {:?}, max_weight: {:?}, weight_credit: {:?}",
|
||||
origin, instructions, max_weight, _weight_credit,
|
||||
);
|
||||
ensure!(T::contains(origin), ());
|
||||
match instructions.first() {
|
||||
Some(UnpaidExecution { weight_limit: Limited(m), .. }) if m.all_gte(max_weight) =>
|
||||
Ok(()),
|
||||
Some(UnpaidExecution { weight_limit: Unlimited, .. }) => Ok(()),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows a message only if it is from a system-level child parachain.
|
||||
pub struct IsChildSystemParachain<ParaId>(PhantomData<ParaId>);
|
||||
impl<ParaId: IsSystem + From<u32>> Contains<MultiLocation> for IsChildSystemParachain<ParaId> {
|
||||
@@ -130,42 +267,43 @@ pub struct AllowKnownQueryResponses<ResponseHandler>(PhantomData<ResponseHandler
|
||||
impl<ResponseHandler: OnResponse> ShouldExecute for AllowKnownQueryResponses<ResponseHandler> {
|
||||
fn should_execute<RuntimeCall>(
|
||||
origin: &MultiLocation,
|
||||
message: &mut Xcm<RuntimeCall>,
|
||||
instructions: &mut [Instruction<RuntimeCall>],
|
||||
_max_weight: Weight,
|
||||
_weight_credit: &mut Weight,
|
||||
) -> Result<(), ()> {
|
||||
log::trace!(
|
||||
target: "xcm::barriers",
|
||||
"AllowKnownQueryResponses origin: {:?}, message: {:?}, max_weight: {:?}, weight_credit: {:?}",
|
||||
origin, message, _max_weight, _weight_credit,
|
||||
"AllowKnownQueryResponses origin: {:?}, instructions: {:?}, max_weight: {:?}, weight_credit: {:?}",
|
||||
origin, instructions, _max_weight, _weight_credit,
|
||||
);
|
||||
match message.0.first() {
|
||||
Some(QueryResponse { query_id, .. })
|
||||
if ResponseHandler::expecting_response(origin, *query_id) =>
|
||||
ensure!(instructions.len() == 1, ());
|
||||
match instructions.first() {
|
||||
Some(QueryResponse { query_id, querier, .. })
|
||||
if ResponseHandler::expecting_response(origin, *query_id, querier.as_ref()) =>
|
||||
Ok(()),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows execution from `origin` if it is just a straight `SubscribeVerison` or
|
||||
/// Allows execution from `origin` if it is just a straight `SubscribeVersion` or
|
||||
/// `UnsubscribeVersion` instruction.
|
||||
pub struct AllowSubscriptionsFrom<T>(PhantomData<T>);
|
||||
impl<T: Contains<MultiLocation>> ShouldExecute for AllowSubscriptionsFrom<T> {
|
||||
fn should_execute<RuntimeCall>(
|
||||
origin: &MultiLocation,
|
||||
message: &mut Xcm<RuntimeCall>,
|
||||
instructions: &mut [Instruction<RuntimeCall>],
|
||||
_max_weight: Weight,
|
||||
_weight_credit: &mut Weight,
|
||||
) -> Result<(), ()> {
|
||||
log::trace!(
|
||||
target: "xcm::barriers",
|
||||
"AllowSubscriptionsFrom origin: {:?}, message: {:?}, max_weight: {:?}, weight_credit: {:?}",
|
||||
origin, message, _max_weight, _weight_credit,
|
||||
"AllowSubscriptionsFrom origin: {:?}, instructions: {:?}, max_weight: {:?}, weight_credit: {:?}",
|
||||
origin, instructions, _max_weight, _weight_credit,
|
||||
);
|
||||
ensure!(T::contains(origin), ());
|
||||
match (message.0.len(), message.0.first()) {
|
||||
(1, Some(SubscribeVersion { .. })) | (1, Some(UnsubscribeVersion)) => Ok(()),
|
||||
match instructions {
|
||||
&mut [SubscribeVersion { .. } | UnsubscribeVersion] => Ok(()),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,11 @@
|
||||
|
||||
//! Adapters to work with `frame_support::traits::Currency` through XCM.
|
||||
|
||||
use super::MintLocation;
|
||||
use frame_support::traits::{ExistenceRequirement::AllowDeath, Get, WithdrawReasons};
|
||||
use sp_runtime::traits::CheckedSub;
|
||||
use sp_std::{marker::PhantomData, result};
|
||||
use xcm::latest::{Error as XcmError, MultiAsset, MultiLocation, Result};
|
||||
use xcm::latest::{Error as XcmError, MultiAsset, MultiLocation, Result, XcmContext};
|
||||
use xcm_executor::{
|
||||
traits::{Convert, MatchesFungible, TransactAsset},
|
||||
Assets,
|
||||
@@ -67,10 +68,13 @@ impl From<Error> for XcmError {
|
||||
/// /// messages from the parent (relay chain).
|
||||
/// pub type LocationConverter = (ParentIsPreset<AccountId>);
|
||||
///
|
||||
/// /// Just a dummy implementation of `Currency`. Normally this would be `Balances`.
|
||||
/// pub type CurrencyImpl = ();
|
||||
///
|
||||
/// /// Final currency adapter. This can be used in `xcm::Config` to specify how asset related transactions happen.
|
||||
/// pub type AssetTransactor = CurrencyAdapter<
|
||||
/// // Use this balance type:
|
||||
/// u128,
|
||||
/// // Use this `Currency` impl instance:
|
||||
/// CurrencyImpl,
|
||||
/// // The matcher: use the currency when the asset is a concrete asset in our relay chain.
|
||||
/// IsConcrete<RelayChain>,
|
||||
/// // The local converter: default account of the parent relay chain.
|
||||
@@ -86,67 +90,108 @@ pub struct CurrencyAdapter<Currency, Matcher, AccountIdConverter, AccountId, Che
|
||||
);
|
||||
|
||||
impl<
|
||||
Currency: frame_support::traits::Currency<AccountId>,
|
||||
Matcher: MatchesFungible<Currency::Balance>,
|
||||
AccountIdConverter: Convert<MultiLocation, AccountId>,
|
||||
Currency: frame_support::traits::Currency<AccountId>,
|
||||
AccountId: Clone, // can't get away without it since Currency is generic over it.
|
||||
CheckedAccount: Get<Option<AccountId>>,
|
||||
CheckedAccount: Get<Option<(AccountId, MintLocation)>>,
|
||||
> CurrencyAdapter<Currency, Matcher, AccountIdConverter, AccountId, CheckedAccount>
|
||||
{
|
||||
fn can_accrue_checked(_checked_account: AccountId, _amount: Currency::Balance) -> Result {
|
||||
Ok(())
|
||||
}
|
||||
fn can_reduce_checked(checked_account: AccountId, amount: Currency::Balance) -> Result {
|
||||
let new_balance = Currency::free_balance(&checked_account)
|
||||
.checked_sub(&amount)
|
||||
.ok_or(XcmError::NotWithdrawable)?;
|
||||
Currency::ensure_can_withdraw(
|
||||
&checked_account,
|
||||
amount,
|
||||
WithdrawReasons::TRANSFER,
|
||||
new_balance,
|
||||
)
|
||||
.map_err(|_| XcmError::NotWithdrawable)
|
||||
}
|
||||
fn accrue_checked(checked_account: AccountId, amount: Currency::Balance) {
|
||||
Currency::deposit_creating(&checked_account, amount);
|
||||
Currency::deactivate(amount);
|
||||
}
|
||||
fn reduce_checked(checked_account: AccountId, amount: Currency::Balance) {
|
||||
let ok =
|
||||
Currency::withdraw(&checked_account, amount, WithdrawReasons::TRANSFER, AllowDeath)
|
||||
.is_ok();
|
||||
if ok {
|
||||
Currency::reactivate(amount);
|
||||
} else {
|
||||
frame_support::defensive!(
|
||||
"`can_check_in` must have returned `true` immediately prior; qed"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
Currency: frame_support::traits::Currency<AccountId>,
|
||||
Matcher: MatchesFungible<Currency::Balance>,
|
||||
AccountIdConverter: Convert<MultiLocation, AccountId>,
|
||||
AccountId: Clone, // can't get away without it since Currency is generic over it.
|
||||
CheckedAccount: Get<Option<(AccountId, MintLocation)>>,
|
||||
> TransactAsset
|
||||
for CurrencyAdapter<Currency, Matcher, AccountIdConverter, AccountId, CheckedAccount>
|
||||
{
|
||||
fn can_check_in(_origin: &MultiLocation, what: &MultiAsset) -> Result {
|
||||
fn can_check_in(_origin: &MultiLocation, what: &MultiAsset, _context: &XcmContext) -> Result {
|
||||
log::trace!(target: "xcm::currency_adapter", "can_check_in origin: {:?}, what: {:?}", _origin, what);
|
||||
// Check we handle this asset.
|
||||
let amount: Currency::Balance =
|
||||
Matcher::matches_fungible(what).ok_or(Error::AssetNotFound)?;
|
||||
if let Some(checked_account) = CheckedAccount::get() {
|
||||
let new_balance = Currency::free_balance(&checked_account)
|
||||
.checked_sub(&amount)
|
||||
.ok_or(XcmError::NotWithdrawable)?;
|
||||
Currency::ensure_can_withdraw(
|
||||
&checked_account,
|
||||
amount,
|
||||
WithdrawReasons::TRANSFER,
|
||||
new_balance,
|
||||
)
|
||||
.map_err(|_| XcmError::NotWithdrawable)?;
|
||||
match CheckedAccount::get() {
|
||||
Some((checked_account, MintLocation::Local)) =>
|
||||
Self::can_reduce_checked(checked_account, amount),
|
||||
Some((checked_account, MintLocation::NonLocal)) =>
|
||||
Self::can_accrue_checked(checked_account, amount),
|
||||
None => Ok(()),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_in(_origin: &MultiLocation, what: &MultiAsset) {
|
||||
fn check_in(_origin: &MultiLocation, what: &MultiAsset, _context: &XcmContext) {
|
||||
log::trace!(target: "xcm::currency_adapter", "check_in origin: {:?}, what: {:?}", _origin, what);
|
||||
if let Some(amount) = Matcher::matches_fungible(what) {
|
||||
if let Some(checked_account) = CheckedAccount::get() {
|
||||
let ok = Currency::withdraw(
|
||||
&checked_account,
|
||||
amount,
|
||||
WithdrawReasons::TRANSFER,
|
||||
AllowDeath,
|
||||
)
|
||||
.is_ok();
|
||||
if ok {
|
||||
Currency::reactivate(amount);
|
||||
}
|
||||
debug_assert!(
|
||||
ok,
|
||||
"`can_check_in` must have returned `true` immediately prior; qed"
|
||||
);
|
||||
match CheckedAccount::get() {
|
||||
Some((checked_account, MintLocation::Local)) =>
|
||||
Self::reduce_checked(checked_account, amount),
|
||||
Some((checked_account, MintLocation::NonLocal)) =>
|
||||
Self::accrue_checked(checked_account, amount),
|
||||
None => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_out(_dest: &MultiLocation, what: &MultiAsset) {
|
||||
fn can_check_out(_dest: &MultiLocation, what: &MultiAsset, _context: &XcmContext) -> Result {
|
||||
log::trace!(target: "xcm::currency_adapter", "check_out dest: {:?}, what: {:?}", _dest, what);
|
||||
let amount = Matcher::matches_fungible(what).ok_or(Error::AssetNotFound)?;
|
||||
match CheckedAccount::get() {
|
||||
Some((checked_account, MintLocation::Local)) =>
|
||||
Self::can_accrue_checked(checked_account, amount),
|
||||
Some((checked_account, MintLocation::NonLocal)) =>
|
||||
Self::can_reduce_checked(checked_account, amount),
|
||||
None => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn check_out(_dest: &MultiLocation, what: &MultiAsset, _context: &XcmContext) {
|
||||
log::trace!(target: "xcm::currency_adapter", "check_out dest: {:?}, what: {:?}", _dest, what);
|
||||
if let Some(amount) = Matcher::matches_fungible(what) {
|
||||
if let Some(checked_account) = CheckedAccount::get() {
|
||||
Currency::deposit_creating(&checked_account, amount);
|
||||
Currency::deactivate(amount);
|
||||
match CheckedAccount::get() {
|
||||
Some((checked_account, MintLocation::Local)) =>
|
||||
Self::accrue_checked(checked_account, amount),
|
||||
Some((checked_account, MintLocation::NonLocal)) =>
|
||||
Self::reduce_checked(checked_account, amount),
|
||||
None => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn deposit_asset(what: &MultiAsset, who: &MultiLocation) -> Result {
|
||||
fn deposit_asset(what: &MultiAsset, who: &MultiLocation, _context: &XcmContext) -> Result {
|
||||
log::trace!(target: "xcm::currency_adapter", "deposit_asset what: {:?}, who: {:?}", what, who);
|
||||
// Check we handle this asset.
|
||||
let amount = Matcher::matches_fungible(&what).ok_or(Error::AssetNotFound)?;
|
||||
@@ -156,7 +201,11 @@ impl<
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn withdraw_asset(what: &MultiAsset, who: &MultiLocation) -> result::Result<Assets, XcmError> {
|
||||
fn withdraw_asset(
|
||||
what: &MultiAsset,
|
||||
who: &MultiLocation,
|
||||
_maybe_context: Option<&XcmContext>,
|
||||
) -> result::Result<Assets, XcmError> {
|
||||
log::trace!(target: "xcm::currency_adapter", "withdraw_asset what: {:?}, who: {:?}", what, who);
|
||||
// Check we handle this asset.
|
||||
let amount = Matcher::matches_fungible(what).ok_or(Error::AssetNotFound)?;
|
||||
@@ -171,6 +220,7 @@ impl<
|
||||
asset: &MultiAsset,
|
||||
from: &MultiLocation,
|
||||
to: &MultiLocation,
|
||||
_context: &XcmContext,
|
||||
) -> result::Result<Assets, XcmError> {
|
||||
log::trace!(target: "xcm::currency_adapter", "internal_transfer_asset asset: {:?}, from: {:?}, to: {:?}", asset, from, to);
|
||||
let amount = Matcher::matches_fungible(asset).ok_or(Error::AssetNotFound)?;
|
||||
|
||||
@@ -14,28 +14,29 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Various implementations of `FilterAssetLocation`.
|
||||
//! Various implementations of `ContainsPair<MultiAsset, MultiLocation>`.
|
||||
|
||||
use frame_support::traits::Get;
|
||||
use frame_support::traits::{ContainsPair, Get};
|
||||
use sp_std::marker::PhantomData;
|
||||
use xcm::latest::{AssetId::Concrete, MultiAsset, MultiAssetFilter, MultiLocation};
|
||||
use xcm_executor::traits::FilterAssetLocation;
|
||||
|
||||
/// Accepts an asset iff it is a native asset.
|
||||
pub struct NativeAsset;
|
||||
impl FilterAssetLocation for NativeAsset {
|
||||
fn filter_asset_location(asset: &MultiAsset, origin: &MultiLocation) -> bool {
|
||||
log::trace!(target: "xcm::filter_asset_location", "NativeAsset asset: {:?}, origin: {:?}", asset, origin);
|
||||
impl ContainsPair<MultiAsset, MultiLocation> for NativeAsset {
|
||||
fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool {
|
||||
log::trace!(target: "xcm::contains", "NativeAsset asset: {:?}, origin: {:?}", asset, origin);
|
||||
matches!(asset.id, Concrete(ref id) if id == origin)
|
||||
}
|
||||
}
|
||||
|
||||
/// Accepts an asset if it is contained in the given `T`'s `Get` implementation.
|
||||
pub struct Case<T>(PhantomData<T>);
|
||||
impl<T: Get<(MultiAssetFilter, MultiLocation)>> FilterAssetLocation for Case<T> {
|
||||
fn filter_asset_location(asset: &MultiAsset, origin: &MultiLocation) -> bool {
|
||||
log::trace!(target: "xcm::filter_asset_location", "Case asset: {:?}, origin: {:?}", asset, origin);
|
||||
impl<T: Get<(MultiAssetFilter, MultiLocation)>> ContainsPair<MultiAsset, MultiLocation>
|
||||
for Case<T>
|
||||
{
|
||||
fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool {
|
||||
log::trace!(target: "xcm::contains", "Case asset: {:?}, origin: {:?}", asset, origin);
|
||||
let (a, o) = T::get();
|
||||
a.contains(asset) && &o == origin
|
||||
a.matches(asset) && &o == origin
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,97 +17,11 @@
|
||||
//! Adapters to work with `frame_support::traits::tokens::fungibles` through XCM.
|
||||
|
||||
use frame_support::traits::{tokens::fungibles, Contains, Get};
|
||||
use sp_std::{borrow::Borrow, marker::PhantomData, prelude::*, result};
|
||||
use xcm::latest::{
|
||||
AssetId::{Abstract, Concrete},
|
||||
Error as XcmError,
|
||||
Fungibility::Fungible,
|
||||
Junction, MultiAsset, MultiLocation, Result,
|
||||
};
|
||||
use sp_std::{marker::PhantomData, prelude::*, result};
|
||||
use xcm::latest::prelude::*;
|
||||
use xcm_executor::traits::{Convert, Error as MatchError, MatchesFungibles, TransactAsset};
|
||||
|
||||
/// Converter struct implementing `AssetIdConversion` converting a numeric asset ID (must be `TryFrom/TryInto<u128>`) into
|
||||
/// a `GeneralIndex` junction, prefixed by some `MultiLocation` value. The `MultiLocation` value will typically be a
|
||||
/// `PalletInstance` junction.
|
||||
pub struct AsPrefixedGeneralIndex<Prefix, AssetId, ConvertAssetId>(
|
||||
PhantomData<(Prefix, AssetId, ConvertAssetId)>,
|
||||
);
|
||||
impl<Prefix: Get<MultiLocation>, AssetId: Clone, ConvertAssetId: Convert<u128, AssetId>>
|
||||
Convert<MultiLocation, AssetId> for AsPrefixedGeneralIndex<Prefix, AssetId, ConvertAssetId>
|
||||
{
|
||||
fn convert_ref(id: impl Borrow<MultiLocation>) -> result::Result<AssetId, ()> {
|
||||
let prefix = Prefix::get();
|
||||
let id = id.borrow();
|
||||
if prefix.parent_count() != id.parent_count() ||
|
||||
prefix
|
||||
.interior()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.any(|(index, junction)| id.interior().at(index) != Some(junction))
|
||||
{
|
||||
return Err(())
|
||||
}
|
||||
match id.interior().at(prefix.interior().len()) {
|
||||
Some(Junction::GeneralIndex(id)) => ConvertAssetId::convert_ref(id),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
fn reverse_ref(what: impl Borrow<AssetId>) -> result::Result<MultiLocation, ()> {
|
||||
let mut location = Prefix::get();
|
||||
let id = ConvertAssetId::reverse_ref(what)?;
|
||||
location.push_interior(Junction::GeneralIndex(id)).map_err(|_| ())?;
|
||||
Ok(location)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ConvertedConcreteAssetId<AssetId, Balance, ConvertAssetId, ConvertBalance>(
|
||||
PhantomData<(AssetId, Balance, ConvertAssetId, ConvertBalance)>,
|
||||
);
|
||||
impl<
|
||||
AssetId: Clone,
|
||||
Balance: Clone,
|
||||
ConvertAssetId: Convert<MultiLocation, AssetId>,
|
||||
ConvertBalance: Convert<u128, Balance>,
|
||||
> MatchesFungibles<AssetId, Balance>
|
||||
for ConvertedConcreteAssetId<AssetId, Balance, ConvertAssetId, ConvertBalance>
|
||||
{
|
||||
fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), MatchError> {
|
||||
let (amount, id) = match (&a.fun, &a.id) {
|
||||
(Fungible(ref amount), Concrete(ref id)) => (amount, id),
|
||||
_ => return Err(MatchError::AssetNotFound),
|
||||
};
|
||||
let what =
|
||||
ConvertAssetId::convert_ref(id).map_err(|_| MatchError::AssetIdConversionFailed)?;
|
||||
let amount = ConvertBalance::convert_ref(amount)
|
||||
.map_err(|_| MatchError::AmountToBalanceConversionFailed)?;
|
||||
Ok((what, amount))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ConvertedAbstractAssetId<AssetId, Balance, ConvertAssetId, ConvertBalance>(
|
||||
PhantomData<(AssetId, Balance, ConvertAssetId, ConvertBalance)>,
|
||||
);
|
||||
impl<
|
||||
AssetId: Clone,
|
||||
Balance: Clone,
|
||||
ConvertAssetId: Convert<Vec<u8>, AssetId>,
|
||||
ConvertBalance: Convert<u128, Balance>,
|
||||
> MatchesFungibles<AssetId, Balance>
|
||||
for ConvertedAbstractAssetId<AssetId, Balance, ConvertAssetId, ConvertBalance>
|
||||
{
|
||||
fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), MatchError> {
|
||||
let (amount, id) = match (&a.fun, &a.id) {
|
||||
(Fungible(ref amount), Abstract(ref id)) => (amount, id),
|
||||
_ => return Err(MatchError::AssetNotFound),
|
||||
};
|
||||
let what =
|
||||
ConvertAssetId::convert_ref(id).map_err(|_| MatchError::AssetIdConversionFailed)?;
|
||||
let amount = ConvertBalance::convert_ref(amount)
|
||||
.map_err(|_| MatchError::AmountToBalanceConversionFailed)?;
|
||||
Ok((what, amount))
|
||||
}
|
||||
}
|
||||
|
||||
/// `TransactAsset` implementation to convert a `fungibles` implementation to become usable in XCM.
|
||||
pub struct FungiblesTransferAdapter<Assets, Matcher, AccountIdConverter, AccountId>(
|
||||
PhantomData<(Assets, Matcher, AccountIdConverter, AccountId)>,
|
||||
);
|
||||
@@ -122,6 +36,7 @@ impl<
|
||||
what: &MultiAsset,
|
||||
from: &MultiLocation,
|
||||
to: &MultiLocation,
|
||||
_context: &XcmContext,
|
||||
) -> result::Result<xcm_executor::Assets, XcmError> {
|
||||
log::trace!(
|
||||
target: "xcm::fungibles_adapter",
|
||||
@@ -140,6 +55,83 @@ impl<
|
||||
}
|
||||
}
|
||||
|
||||
/// The location which is allowed to mint a particular asset.
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub enum MintLocation {
|
||||
/// This chain is allowed to mint the asset. When we track teleports of the asset we ensure that
|
||||
/// no more of the asset returns back to the chain than has been sent out.
|
||||
Local,
|
||||
/// This chain is not allowed to mint the asset. When we track teleports of the asset we ensure
|
||||
/// that no more of the asset is sent out from the chain than has been previously received.
|
||||
NonLocal,
|
||||
}
|
||||
|
||||
/// Simple trait to indicate whether an asset is subject to having its teleportation into and out of
|
||||
/// this chain recorded and if so in what `MintLocation`.
|
||||
///
|
||||
/// The overall purpose of asset-checking is to ensure either no more assets are teleported into a
|
||||
/// chain than the outstanding balance of assets which were previously teleported out (as in the
|
||||
/// case of locally-minted assets); or that no more assets are teleported out of a chain than the
|
||||
/// outstanding balance of assets which have previously been teleported in (as in the case of chains
|
||||
/// where the `asset` is not minted locally).
|
||||
pub trait AssetChecking<AssetId> {
|
||||
/// Return the teleportation asset-checking policy for the given `asset`. `None` implies no
|
||||
/// checking. Otherwise the policy detailed by the inner `MintLocation` should be respected by
|
||||
/// teleportation.
|
||||
fn asset_checking(asset: &AssetId) -> Option<MintLocation>;
|
||||
}
|
||||
|
||||
/// Implementation of `AssetChecking` which subjects no assets to having their teleportations
|
||||
/// recorded.
|
||||
pub struct NoChecking;
|
||||
impl<AssetId> AssetChecking<AssetId> for NoChecking {
|
||||
fn asset_checking(_: &AssetId) -> Option<MintLocation> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of `AssetChecking` which subjects a given set of assets `T` to having their
|
||||
/// teleportations recorded with a `MintLocation::Local`.
|
||||
pub struct LocalMint<T>(sp_std::marker::PhantomData<T>);
|
||||
impl<AssetId, T: Contains<AssetId>> AssetChecking<AssetId> for LocalMint<T> {
|
||||
fn asset_checking(asset: &AssetId) -> Option<MintLocation> {
|
||||
match T::contains(asset) {
|
||||
true => Some(MintLocation::Local),
|
||||
false => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of `AssetChecking` which subjects a given set of assets `T` to having their
|
||||
/// teleportations recorded with a `MintLocation::NonLocal`.
|
||||
pub struct NonLocalMint<T>(sp_std::marker::PhantomData<T>);
|
||||
impl<AssetId, T: Contains<AssetId>> AssetChecking<AssetId> for NonLocalMint<T> {
|
||||
fn asset_checking(asset: &AssetId) -> Option<MintLocation> {
|
||||
match T::contains(asset) {
|
||||
true => Some(MintLocation::NonLocal),
|
||||
false => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of `AssetChecking` which subjects a given set of assets `L` to having their
|
||||
/// teleportations recorded with a `MintLocation::Local` and a second set of assets `R` to having
|
||||
/// their teleportations recorded with a `MintLocation::NonLocal`.
|
||||
pub struct DualMint<L, R>(sp_std::marker::PhantomData<(L, R)>);
|
||||
impl<AssetId, L: Contains<AssetId>, R: Contains<AssetId>> AssetChecking<AssetId>
|
||||
for DualMint<L, R>
|
||||
{
|
||||
fn asset_checking(asset: &AssetId) -> Option<MintLocation> {
|
||||
if L::contains(asset) {
|
||||
Some(MintLocation::Local)
|
||||
} else if R::contains(asset) {
|
||||
Some(MintLocation::NonLocal)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FungiblesMutateAdapter<
|
||||
Assets,
|
||||
Matcher,
|
||||
@@ -148,12 +140,48 @@ pub struct FungiblesMutateAdapter<
|
||||
CheckAsset,
|
||||
CheckingAccount,
|
||||
>(PhantomData<(Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount)>);
|
||||
|
||||
impl<
|
||||
Assets: fungibles::Mutate<AccountId>,
|
||||
Matcher: MatchesFungibles<Assets::AssetId, Assets::Balance>,
|
||||
AccountIdConverter: Convert<MultiLocation, AccountId>,
|
||||
AccountId: Clone, // can't get away without it since Currency is generic over it.
|
||||
CheckAsset: Contains<Assets::AssetId>,
|
||||
CheckAsset: AssetChecking<Assets::AssetId>,
|
||||
CheckingAccount: Get<AccountId>,
|
||||
>
|
||||
FungiblesMutateAdapter<Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount>
|
||||
{
|
||||
fn can_accrue_checked(asset_id: Assets::AssetId, amount: Assets::Balance) -> XcmResult {
|
||||
let checking_account = CheckingAccount::get();
|
||||
Assets::can_deposit(asset_id, &checking_account, amount, true)
|
||||
.into_result()
|
||||
.map_err(|_| XcmError::NotDepositable)
|
||||
}
|
||||
fn can_reduce_checked(asset_id: Assets::AssetId, amount: Assets::Balance) -> XcmResult {
|
||||
let checking_account = CheckingAccount::get();
|
||||
Assets::can_withdraw(asset_id, &checking_account, amount)
|
||||
.into_result()
|
||||
.map_err(|_| XcmError::NotWithdrawable)
|
||||
.map(|_| ())
|
||||
}
|
||||
fn accrue_checked(asset_id: Assets::AssetId, amount: Assets::Balance) {
|
||||
let checking_account = CheckingAccount::get();
|
||||
let ok = Assets::mint_into(asset_id, &checking_account, amount).is_ok();
|
||||
debug_assert!(ok, "`can_accrue_checked` must have returned `true` immediately prior; qed");
|
||||
}
|
||||
fn reduce_checked(asset_id: Assets::AssetId, amount: Assets::Balance) {
|
||||
let checking_account = CheckingAccount::get();
|
||||
let ok = Assets::burn_from(asset_id, &checking_account, amount).is_ok();
|
||||
debug_assert!(ok, "`can_reduce_checked` must have returned `true` immediately prior; qed");
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
Assets: fungibles::Mutate<AccountId>,
|
||||
Matcher: MatchesFungibles<Assets::AssetId, Assets::Balance>,
|
||||
AccountIdConverter: Convert<MultiLocation, AccountId>,
|
||||
AccountId: Clone, // can't get away without it since Currency is generic over it.
|
||||
CheckAsset: AssetChecking<Assets::AssetId>,
|
||||
CheckingAccount: Get<AccountId>,
|
||||
> TransactAsset
|
||||
for FungiblesMutateAdapter<
|
||||
@@ -165,7 +193,11 @@ impl<
|
||||
CheckingAccount,
|
||||
>
|
||||
{
|
||||
fn can_check_in(_origin: &MultiLocation, what: &MultiAsset) -> Result {
|
||||
fn can_check_in(
|
||||
_origin: &MultiLocation,
|
||||
what: &MultiAsset,
|
||||
_context: &XcmContext,
|
||||
) -> XcmResult {
|
||||
log::trace!(
|
||||
target: "xcm::fungibles_adapter",
|
||||
"can_check_in origin: {:?}, what: {:?}",
|
||||
@@ -173,50 +205,71 @@ impl<
|
||||
);
|
||||
// Check we handle this asset.
|
||||
let (asset_id, amount) = Matcher::matches_fungibles(what)?;
|
||||
if CheckAsset::contains(&asset_id) {
|
||||
// This is an asset whose teleports we track.
|
||||
let checking_account = CheckingAccount::get();
|
||||
Assets::can_withdraw(asset_id, &checking_account, amount)
|
||||
.into_result()
|
||||
.map_err(|_| XcmError::NotWithdrawable)?;
|
||||
match CheckAsset::asset_checking(&asset_id) {
|
||||
// We track this asset's teleports to ensure no more come in than have gone out.
|
||||
Some(MintLocation::Local) => Self::can_reduce_checked(asset_id, amount),
|
||||
// We track this asset's teleports to ensure no more go out than have come in.
|
||||
Some(MintLocation::NonLocal) => Self::can_accrue_checked(asset_id, amount),
|
||||
_ => Ok(()),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_in(_origin: &MultiLocation, what: &MultiAsset) {
|
||||
fn check_in(_origin: &MultiLocation, what: &MultiAsset, _context: &XcmContext) {
|
||||
log::trace!(
|
||||
target: "xcm::fungibles_adapter",
|
||||
"check_in origin: {:?}, what: {:?}",
|
||||
_origin, what
|
||||
);
|
||||
if let Ok((asset_id, amount)) = Matcher::matches_fungibles(what) {
|
||||
if CheckAsset::contains(&asset_id) {
|
||||
let checking_account = CheckingAccount::get();
|
||||
let ok = Assets::burn_from(asset_id, &checking_account, amount).is_ok();
|
||||
debug_assert!(
|
||||
ok,
|
||||
"`can_check_in` must have returned `true` immediately prior; qed"
|
||||
);
|
||||
match CheckAsset::asset_checking(&asset_id) {
|
||||
// We track this asset's teleports to ensure no more come in than have gone out.
|
||||
Some(MintLocation::Local) => Self::reduce_checked(asset_id, amount),
|
||||
// We track this asset's teleports to ensure no more go out than have come in.
|
||||
Some(MintLocation::NonLocal) => Self::accrue_checked(asset_id, amount),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_out(_dest: &MultiLocation, what: &MultiAsset) {
|
||||
fn can_check_out(
|
||||
_origin: &MultiLocation,
|
||||
what: &MultiAsset,
|
||||
_context: &XcmContext,
|
||||
) -> XcmResult {
|
||||
log::trace!(
|
||||
target: "xcm::fungibles_adapter",
|
||||
"can_check_in origin: {:?}, what: {:?}",
|
||||
_origin, what
|
||||
);
|
||||
// Check we handle this asset.
|
||||
let (asset_id, amount) = Matcher::matches_fungibles(what)?;
|
||||
match CheckAsset::asset_checking(&asset_id) {
|
||||
// We track this asset's teleports to ensure no more come in than have gone out.
|
||||
Some(MintLocation::Local) => Self::can_accrue_checked(asset_id, amount),
|
||||
// We track this asset's teleports to ensure no more go out than have come in.
|
||||
Some(MintLocation::NonLocal) => Self::can_reduce_checked(asset_id, amount),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn check_out(_dest: &MultiLocation, what: &MultiAsset, _context: &XcmContext) {
|
||||
log::trace!(
|
||||
target: "xcm::fungibles_adapter",
|
||||
"check_out dest: {:?}, what: {:?}",
|
||||
_dest, what
|
||||
);
|
||||
if let Ok((asset_id, amount)) = Matcher::matches_fungibles(what) {
|
||||
if CheckAsset::contains(&asset_id) {
|
||||
let checking_account = CheckingAccount::get();
|
||||
let ok = Assets::mint_into(asset_id, &checking_account, amount).is_ok();
|
||||
debug_assert!(ok, "`mint_into` cannot generally fail; qed");
|
||||
match CheckAsset::asset_checking(&asset_id) {
|
||||
// We track this asset's teleports to ensure no more come in than have gone out.
|
||||
Some(MintLocation::Local) => Self::accrue_checked(asset_id, amount),
|
||||
// We track this asset's teleports to ensure no more go out than have come in.
|
||||
Some(MintLocation::NonLocal) => Self::reduce_checked(asset_id, amount),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn deposit_asset(what: &MultiAsset, who: &MultiLocation) -> Result {
|
||||
fn deposit_asset(what: &MultiAsset, who: &MultiLocation, _context: &XcmContext) -> XcmResult {
|
||||
log::trace!(
|
||||
target: "xcm::fungibles_adapter",
|
||||
"deposit_asset what: {:?}, who: {:?}",
|
||||
@@ -233,6 +286,7 @@ impl<
|
||||
fn withdraw_asset(
|
||||
what: &MultiAsset,
|
||||
who: &MultiLocation,
|
||||
_maybe_context: Option<&XcmContext>,
|
||||
) -> result::Result<xcm_executor::Assets, XcmError> {
|
||||
log::trace!(
|
||||
target: "xcm::fungibles_adapter",
|
||||
@@ -262,12 +316,12 @@ impl<
|
||||
Matcher: MatchesFungibles<Assets::AssetId, Assets::Balance>,
|
||||
AccountIdConverter: Convert<MultiLocation, AccountId>,
|
||||
AccountId: Clone, // can't get away without it since Currency is generic over it.
|
||||
CheckAsset: Contains<Assets::AssetId>,
|
||||
CheckAsset: AssetChecking<Assets::AssetId>,
|
||||
CheckingAccount: Get<AccountId>,
|
||||
> TransactAsset
|
||||
for FungiblesAdapter<Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount>
|
||||
{
|
||||
fn can_check_in(origin: &MultiLocation, what: &MultiAsset) -> Result {
|
||||
fn can_check_in(origin: &MultiLocation, what: &MultiAsset, context: &XcmContext) -> XcmResult {
|
||||
FungiblesMutateAdapter::<
|
||||
Assets,
|
||||
Matcher,
|
||||
@@ -275,10 +329,10 @@ impl<
|
||||
AccountId,
|
||||
CheckAsset,
|
||||
CheckingAccount,
|
||||
>::can_check_in(origin, what)
|
||||
>::can_check_in(origin, what, context)
|
||||
}
|
||||
|
||||
fn check_in(origin: &MultiLocation, what: &MultiAsset) {
|
||||
fn check_in(origin: &MultiLocation, what: &MultiAsset, context: &XcmContext) {
|
||||
FungiblesMutateAdapter::<
|
||||
Assets,
|
||||
Matcher,
|
||||
@@ -286,10 +340,10 @@ impl<
|
||||
AccountId,
|
||||
CheckAsset,
|
||||
CheckingAccount,
|
||||
>::check_in(origin, what)
|
||||
>::check_in(origin, what, context)
|
||||
}
|
||||
|
||||
fn check_out(dest: &MultiLocation, what: &MultiAsset) {
|
||||
fn can_check_out(dest: &MultiLocation, what: &MultiAsset, context: &XcmContext) -> XcmResult {
|
||||
FungiblesMutateAdapter::<
|
||||
Assets,
|
||||
Matcher,
|
||||
@@ -297,10 +351,10 @@ impl<
|
||||
AccountId,
|
||||
CheckAsset,
|
||||
CheckingAccount,
|
||||
>::check_out(dest, what)
|
||||
>::can_check_out(dest, what, context)
|
||||
}
|
||||
|
||||
fn deposit_asset(what: &MultiAsset, who: &MultiLocation) -> Result {
|
||||
fn check_out(dest: &MultiLocation, what: &MultiAsset, context: &XcmContext) {
|
||||
FungiblesMutateAdapter::<
|
||||
Assets,
|
||||
Matcher,
|
||||
@@ -308,12 +362,24 @@ impl<
|
||||
AccountId,
|
||||
CheckAsset,
|
||||
CheckingAccount,
|
||||
>::deposit_asset(what, who)
|
||||
>::check_out(dest, what, context)
|
||||
}
|
||||
|
||||
fn deposit_asset(what: &MultiAsset, who: &MultiLocation, context: &XcmContext) -> XcmResult {
|
||||
FungiblesMutateAdapter::<
|
||||
Assets,
|
||||
Matcher,
|
||||
AccountIdConverter,
|
||||
AccountId,
|
||||
CheckAsset,
|
||||
CheckingAccount,
|
||||
>::deposit_asset(what, who, context)
|
||||
}
|
||||
|
||||
fn withdraw_asset(
|
||||
what: &MultiAsset,
|
||||
who: &MultiLocation,
|
||||
maybe_context: Option<&XcmContext>,
|
||||
) -> result::Result<xcm_executor::Assets, XcmError> {
|
||||
FungiblesMutateAdapter::<
|
||||
Assets,
|
||||
@@ -322,16 +388,17 @@ impl<
|
||||
AccountId,
|
||||
CheckAsset,
|
||||
CheckingAccount,
|
||||
>::withdraw_asset(what, who)
|
||||
>::withdraw_asset(what, who, maybe_context)
|
||||
}
|
||||
|
||||
fn internal_transfer_asset(
|
||||
what: &MultiAsset,
|
||||
from: &MultiLocation,
|
||||
to: &MultiLocation,
|
||||
context: &XcmContext,
|
||||
) -> result::Result<xcm_executor::Assets, XcmError> {
|
||||
FungiblesTransferAdapter::<Assets, Matcher, AccountIdConverter, AccountId>::internal_transfer_asset(
|
||||
what, from, to,
|
||||
what, from, to, context
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
#[cfg(test)]
|
||||
mod mock;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
@@ -31,7 +29,7 @@ pub mod test_utils;
|
||||
mod location_conversion;
|
||||
pub use location_conversion::{
|
||||
Account32Hash, AccountId32Aliases, AccountKey20Aliases, ChildParachainConvertsVia,
|
||||
LocationInverter, ParentIsPreset, SiblingParachainConvertsVia,
|
||||
ParentIsPreset, SiblingParachainConvertsVia,
|
||||
};
|
||||
|
||||
mod origin_conversion;
|
||||
@@ -42,10 +40,16 @@ pub use origin_conversion::{
|
||||
SignedToAccountId32, SovereignSignedViaLocation,
|
||||
};
|
||||
|
||||
mod asset_conversion;
|
||||
pub use asset_conversion::{AsPrefixedGeneralIndex, ConvertedAbstractId, ConvertedConcreteId};
|
||||
#[allow(deprecated)]
|
||||
pub use asset_conversion::{ConvertedAbstractAssetId, ConvertedConcreteAssetId};
|
||||
|
||||
mod barriers;
|
||||
pub use barriers::{
|
||||
AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom,
|
||||
AllowUnpaidExecutionFrom, IsChildSystemParachain, TakeWeightCredit,
|
||||
AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom,
|
||||
AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, IsChildSystemParachain,
|
||||
TakeWeightCredit, WithComputedOrigin,
|
||||
};
|
||||
|
||||
mod currency_adapter;
|
||||
@@ -53,19 +57,29 @@ pub use currency_adapter::CurrencyAdapter;
|
||||
|
||||
mod fungibles_adapter;
|
||||
pub use fungibles_adapter::{
|
||||
AsPrefixedGeneralIndex, ConvertedAbstractAssetId, ConvertedConcreteAssetId, FungiblesAdapter,
|
||||
FungiblesMutateAdapter, FungiblesTransferAdapter,
|
||||
AssetChecking, DualMint, FungiblesAdapter, FungiblesMutateAdapter, FungiblesTransferAdapter,
|
||||
LocalMint, MintLocation, NoChecking, NonLocalMint,
|
||||
};
|
||||
|
||||
mod nonfungibles_adapter;
|
||||
pub use nonfungibles_adapter::{
|
||||
NonFungiblesAdapter, NonFungiblesMutateAdapter, NonFungiblesTransferAdapter,
|
||||
};
|
||||
|
||||
mod weight;
|
||||
#[allow(deprecated)]
|
||||
pub use weight::FixedRateOfConcreteFungible;
|
||||
pub use weight::{
|
||||
FixedRateOfFungible, FixedWeightBounds, TakeRevenue, UsingComponents, WeightInfoBounds,
|
||||
};
|
||||
|
||||
mod matches_fungible;
|
||||
pub use matches_fungible::{IsAbstract, IsConcrete};
|
||||
mod matches_token;
|
||||
pub use matches_token::{IsAbstract, IsConcrete};
|
||||
|
||||
mod filter_asset_location;
|
||||
pub use filter_asset_location::{Case, NativeAsset};
|
||||
|
||||
mod universal_exports;
|
||||
pub use universal_exports::{
|
||||
BridgeBlobDispatcher, BridgeMessage, DispatchBlob, DispatchBlobError, ExporterFor, HaulBlob,
|
||||
HaulBlobExporter, NetworkExportTable, SovereignPaidRemoteExporter, UnpaidLocalExporter,
|
||||
UnpaidRemoteExporter,
|
||||
};
|
||||
|
||||
@@ -19,11 +19,11 @@ use parity_scale_codec::{Decode, Encode};
|
||||
use sp_io::hashing::blake2_256;
|
||||
use sp_runtime::traits::{AccountIdConversion, TrailingZeroInput};
|
||||
use sp_std::{borrow::Borrow, marker::PhantomData};
|
||||
use xcm::latest::{Junction::*, Junctions::*, MultiLocation, NetworkId, Parent};
|
||||
use xcm_executor::traits::{Convert, InvertLocation};
|
||||
use xcm::latest::prelude::*;
|
||||
use xcm_executor::traits::Convert;
|
||||
|
||||
pub struct Account32Hash<Network, AccountId>(PhantomData<(Network, AccountId)>);
|
||||
impl<Network: Get<NetworkId>, AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone>
|
||||
impl<Network: Get<Option<NetworkId>>, AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone>
|
||||
Convert<MultiLocation, AccountId> for Account32Hash<Network, AccountId>
|
||||
{
|
||||
fn convert_ref(location: impl Borrow<MultiLocation>) -> Result<AccountId, ()> {
|
||||
@@ -107,15 +107,12 @@ impl<ParaId: From<u32> + Into<u32> + AccountIdConversion<AccountId>, AccountId:
|
||||
|
||||
/// Extracts the `AccountId32` from the passed `location` if the network matches.
|
||||
pub struct AccountId32Aliases<Network, AccountId>(PhantomData<(Network, AccountId)>);
|
||||
impl<Network: Get<NetworkId>, AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone>
|
||||
impl<Network: Get<Option<NetworkId>>, AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone>
|
||||
Convert<MultiLocation, AccountId> for AccountId32Aliases<Network, AccountId>
|
||||
{
|
||||
fn convert(location: MultiLocation) -> Result<AccountId, MultiLocation> {
|
||||
let id = match location {
|
||||
MultiLocation {
|
||||
parents: 0,
|
||||
interior: X1(AccountId32 { id, network: NetworkId::Any }),
|
||||
} => id,
|
||||
MultiLocation { parents: 0, interior: X1(AccountId32 { id, network: None }) } => id,
|
||||
MultiLocation { parents: 0, interior: X1(AccountId32 { id, network }) }
|
||||
if network == Network::get() =>
|
||||
id,
|
||||
@@ -130,15 +127,12 @@ impl<Network: Get<NetworkId>, AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone
|
||||
}
|
||||
|
||||
pub struct AccountKey20Aliases<Network, AccountId>(PhantomData<(Network, AccountId)>);
|
||||
impl<Network: Get<NetworkId>, AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone>
|
||||
impl<Network: Get<Option<NetworkId>>, AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone>
|
||||
Convert<MultiLocation, AccountId> for AccountKey20Aliases<Network, AccountId>
|
||||
{
|
||||
fn convert(location: MultiLocation) -> Result<AccountId, MultiLocation> {
|
||||
let key = match location {
|
||||
MultiLocation {
|
||||
parents: 0,
|
||||
interior: X1(AccountKey20 { key, network: NetworkId::Any }),
|
||||
} => key,
|
||||
MultiLocation { parents: 0, interior: X1(AccountKey20 { key, network: None }) } => key,
|
||||
MultiLocation { parents: 0, interior: X1(AccountKey20 { key, network }) }
|
||||
if network == Network::get() =>
|
||||
key,
|
||||
@@ -153,69 +147,19 @@ impl<Network: Get<NetworkId>, AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone
|
||||
}
|
||||
}
|
||||
|
||||
/// Simple location inverter; give it this location's ancestry and it'll figure out the inverted
|
||||
/// location.
|
||||
///
|
||||
/// # Example
|
||||
/// ## Network Topology
|
||||
/// ```txt
|
||||
/// v Source
|
||||
/// Relay -> Para 1 -> Account20
|
||||
/// -> Para 2 -> Account32
|
||||
/// ^ Target
|
||||
/// ```
|
||||
/// ```rust
|
||||
/// # use frame_support::parameter_types;
|
||||
/// # use xcm::latest::{MultiLocation, Junction::*, Junctions::{self, *}, NetworkId::Any};
|
||||
/// # use xcm_builder::LocationInverter;
|
||||
/// # use xcm_executor::traits::InvertLocation;
|
||||
/// # fn main() {
|
||||
/// parameter_types!{
|
||||
/// pub Ancestry: MultiLocation = X2(
|
||||
/// Parachain(1),
|
||||
/// AccountKey20 { network: Any, key: Default::default() },
|
||||
/// ).into();
|
||||
/// }
|
||||
///
|
||||
/// let input = MultiLocation::new(2, X2(Parachain(2), AccountId32 { network: Any, id: Default::default() }));
|
||||
/// let inverted = LocationInverter::<Ancestry>::invert_location(&input);
|
||||
/// assert_eq!(inverted, Ok(MultiLocation::new(
|
||||
/// 2,
|
||||
/// X2(Parachain(1), AccountKey20 { network: Any, key: Default::default() }),
|
||||
/// )));
|
||||
/// # }
|
||||
/// ```
|
||||
pub struct LocationInverter<Ancestry>(PhantomData<Ancestry>);
|
||||
impl<Ancestry: Get<MultiLocation>> InvertLocation for LocationInverter<Ancestry> {
|
||||
fn ancestry() -> MultiLocation {
|
||||
Ancestry::get()
|
||||
}
|
||||
fn invert_location(location: &MultiLocation) -> Result<MultiLocation, ()> {
|
||||
let mut ancestry = Ancestry::get();
|
||||
let mut junctions = Here;
|
||||
for _ in 0..location.parent_count() {
|
||||
junctions = junctions
|
||||
.pushed_with(ancestry.take_first_interior().unwrap_or(OnlyChild))
|
||||
.map_err(|_| ())?;
|
||||
}
|
||||
let parents = location.interior().len() as u8;
|
||||
Ok(MultiLocation::new(parents, junctions))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use frame_support::parameter_types;
|
||||
use xcm::latest::{Junction, NetworkId::Any};
|
||||
use xcm::latest::Junction;
|
||||
|
||||
fn account20() -> Junction {
|
||||
AccountKey20 { network: Any, key: Default::default() }
|
||||
AccountKey20 { network: None, key: Default::default() }
|
||||
}
|
||||
|
||||
fn account32() -> Junction {
|
||||
AccountId32 { network: Any, id: Default::default() }
|
||||
AccountId32 { network: None, id: Default::default() }
|
||||
}
|
||||
|
||||
// Network Topology
|
||||
@@ -227,17 +171,17 @@ mod tests {
|
||||
// Inputs and outputs written as file paths:
|
||||
//
|
||||
// input location (source to target): ../../../para_2/account32_default
|
||||
// ancestry (root to source): para_1/account20_default/account20_default
|
||||
// context (root to source): para_1/account20_default/account20_default
|
||||
// =>
|
||||
// output (target to source): ../../para_1/account20_default/account20_default
|
||||
#[test]
|
||||
fn inverter_works_in_tree() {
|
||||
parameter_types! {
|
||||
pub Ancestry: MultiLocation = X3(Parachain(1), account20(), account20()).into();
|
||||
pub UniversalLocation: InteriorMultiLocation = X3(Parachain(1), account20(), account20());
|
||||
}
|
||||
|
||||
let input = MultiLocation::new(3, X2(Parachain(2), account32()));
|
||||
let inverted = LocationInverter::<Ancestry>::invert_location(&input).unwrap();
|
||||
let inverted = UniversalLocation::get().invert_target(&input).unwrap();
|
||||
assert_eq!(inverted, MultiLocation::new(2, X3(Parachain(1), account20(), account20())));
|
||||
}
|
||||
|
||||
@@ -246,13 +190,13 @@ mod tests {
|
||||
// Relay -> Para 1 -> SmartContract -> Account
|
||||
// ^ Target
|
||||
#[test]
|
||||
fn inverter_uses_ancestry_as_inverted_location() {
|
||||
fn inverter_uses_context_as_inverted_location() {
|
||||
parameter_types! {
|
||||
pub Ancestry: MultiLocation = X2(account20(), account20()).into();
|
||||
pub UniversalLocation: InteriorMultiLocation = X2(account20(), account20());
|
||||
}
|
||||
|
||||
let input = MultiLocation::grandparent();
|
||||
let inverted = LocationInverter::<Ancestry>::invert_location(&input).unwrap();
|
||||
let inverted = UniversalLocation::get().invert_target(&input).unwrap();
|
||||
assert_eq!(inverted, X2(account20(), account20()).into());
|
||||
}
|
||||
|
||||
@@ -261,24 +205,24 @@ mod tests {
|
||||
// Relay -> Para 1 -> CollectivePallet -> Plurality
|
||||
// ^ Target
|
||||
#[test]
|
||||
fn inverter_uses_only_child_on_missing_ancestry() {
|
||||
fn inverter_uses_only_child_on_missing_context() {
|
||||
parameter_types! {
|
||||
pub Ancestry: MultiLocation = X1(PalletInstance(5)).into();
|
||||
pub UniversalLocation: InteriorMultiLocation = PalletInstance(5).into();
|
||||
}
|
||||
|
||||
let input = MultiLocation::grandparent();
|
||||
let inverted = LocationInverter::<Ancestry>::invert_location(&input).unwrap();
|
||||
assert_eq!(inverted, X2(PalletInstance(5), OnlyChild).into());
|
||||
let inverted = UniversalLocation::get().invert_target(&input).unwrap();
|
||||
assert_eq!(inverted, (OnlyChild, PalletInstance(5)).into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inverter_errors_when_location_is_too_large() {
|
||||
parameter_types! {
|
||||
pub Ancestry: MultiLocation = Here.into();
|
||||
pub UniversalLocation: InteriorMultiLocation = Here;
|
||||
}
|
||||
|
||||
let input = MultiLocation { parents: 99, interior: X1(Parachain(88)) };
|
||||
let inverted = LocationInverter::<Ancestry>::invert_location(&input);
|
||||
let inverted = UniversalLocation::get().invert_target(&input);
|
||||
assert_eq!(inverted, Err(()));
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user