// Copyright (C) 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 . //! Pallet that serves no other purpose than benchmarking raw messages [`Xcm`]. #![cfg_attr(not(feature = "std"), no_std)] use codec::Encode; use frame_benchmarking::{account, BenchmarkError}; use sp_std::prelude::*; use xcm::latest::prelude::*; use xcm_executor::{ traits::{ConvertLocation, FeeReason}, Config as XcmConfig, FeesMode, }; pub mod fungible; pub mod generic; #[cfg(test)] mod mock; /// A base trait for all individual pallets pub trait Config: frame_system::Config { /// The XCM configurations. /// /// These might affect the execution of XCM messages, such as defining how the /// `TransactAsset` is implemented. type XcmConfig: XcmConfig; /// A converter between a location to a sovereign account. type AccountIdConverter: ConvertLocation; /// Helper that ensures successful delivery for XCM instructions which need `SendXcm`. type DeliveryHelper: EnsureDelivery; /// Does any necessary setup to create a valid destination for XCM messages. /// Returns that destination's location to be used in benchmarks. fn valid_destination() -> Result; /// Worst case scenario for a holding account in this runtime. fn worst_case_holding(depositable_count: u32) -> Assets; } const SEED: u32 = 0; /// The XCM executor to use for doing stuff. pub type ExecutorOf = xcm_executor::XcmExecutor<::XcmConfig>; /// The overarching call type. pub type OverArchingCallOf = ::RuntimeCall; /// The asset transactor of our executor pub type AssetTransactorOf = <::XcmConfig as XcmConfig>::AssetTransactor; /// The call type of executor's config. Should eventually resolve to the same overarching call type. pub type XcmCallOf = <::XcmConfig as XcmConfig>::RuntimeCall; pub fn mock_worst_case_holding(depositable_count: u32, max_assets: u32) -> Assets { let fungibles_amount: u128 = 100; let holding_fungibles = max_assets / 2 - depositable_count; let holding_non_fungibles = holding_fungibles; (0..holding_fungibles) .map(|i| { Asset { id: AssetId(GeneralIndex(i as u128).into()), fun: Fungible(fungibles_amount * i as u128), } .into() }) .chain(core::iter::once(Asset { id: AssetId(Here.into()), fun: Fungible(u128::MAX) })) .chain((0..holding_non_fungibles).map(|i| Asset { id: AssetId(GeneralIndex(i as u128).into()), fun: NonFungible(asset_instance_from(i)), })) .collect::>() .into() } pub fn asset_instance_from(x: u32) -> AssetInstance { let bytes = x.encode(); let mut instance = [0u8; 4]; instance.copy_from_slice(&bytes); AssetInstance::Array4(instance) } pub fn new_executor(origin: Location) -> ExecutorOf { ExecutorOf::::new(origin, [0; 32]) } /// Build a location from an account id. fn account_id_junction(index: u32) -> Junction { let account: T::AccountId = account("account", index, SEED); let mut encoded = account.encode(); encoded.resize(32, 0u8); let mut id = [0u8; 32]; id.copy_from_slice(&encoded); Junction::AccountId32 { network: None, id } } pub fn account_and_location(index: u32) -> (T::AccountId, Location) { let location: Location = account_id_junction::(index).into(); let account = T::AccountIdConverter::convert_location(&location).unwrap(); (account, location) } /// Trait for a type which ensures all requirements for successful delivery with XCM transport /// layers. pub trait EnsureDelivery { /// Prepare all requirements for successful `XcmSender: SendXcm` passing (accounts, balances, /// channels ...). Returns: /// - possible `FeesMode` which is expected to be set to executor /// - possible `Assets` which are expected to be subsume to the Holding Register fn ensure_successful_delivery( origin_ref: &Location, dest: &Location, fee_reason: FeeReason, ) -> (Option, Option); } /// `()` implementation does nothing which means no special requirements for environment. impl EnsureDelivery for () { fn ensure_successful_delivery( _origin_ref: &Location, _dest: &Location, _fee_reason: FeeReason, ) -> (Option, Option) { // doing nothing (None, None) } }