Skip to content
lib.rs 36.4 KiB
Newer Older
// 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 <http://www.gnu.org/licenses/>.

#![cfg_attr(not(feature = "std"), no_std)]

use frame_support::{
Gavin Wood's avatar
Gavin Wood committed
	dispatch::GetDispatchInfo,
Gavin Wood's avatar
Gavin Wood committed
	traits::{Contains, ContainsPair, Get, PalletsInfoAccess},
Gavin Wood's avatar
Gavin Wood committed
use parity_scale_codec::{Decode, Encode};
use sp_core::defer;
use sp_io::hashing::blake2_128;
use sp_std::{fmt::Debug, marker::PhantomData, prelude::*};
Gavin Wood's avatar
Gavin Wood committed
use sp_weights::Weight;
use xcm::latest::prelude::*;
Gavin Wood's avatar
Gavin Wood committed
use traits::{
Gavin Wood's avatar
Gavin Wood committed
	validate_export, AssetExchange, AssetLock, CallDispatcher, ClaimAssets, ConvertOrigin,
	DropAssets, Enact, ExportXcm, FeeManager, FeeReason, OnResponse, Properties, ShouldExecute,
	TransactAsset, VersionChangeNotifier, WeightBounds, WeightTrader, XcmAssetTransfers,
Gavin Wood's avatar
Gavin Wood committed
};
Gavin Wood's avatar
Gavin Wood committed
mod assets;
Francisco Aguirre's avatar
Francisco Aguirre committed
pub use assets::AssetsInHolding;
Gavin Wood's avatar
Gavin Wood committed
mod config;
pub use config::Config;

Gavin Wood's avatar
Gavin Wood committed
/// A struct to specify how fees are being paid.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct FeesMode {
	/// If true, then the fee assets are taken directly from the origin's on-chain account,
	/// otherwise the fee assets are taken from the holding register.
	///
	/// Defaults to false.
	pub jit_withdraw: bool,
}

const RECURSION_LIMIT: u8 = 10;

environmental::environmental!(recursion_count: u8);

/// The XCM executor.
pub struct XcmExecutor<Config: config::Config> {
Francisco Aguirre's avatar
Francisco Aguirre committed
	holding: AssetsInHolding,
Gavin Wood's avatar
Gavin Wood committed
	holding_limit: usize,
	context: XcmContext,
Francisco Aguirre's avatar
Francisco Aguirre committed
	original_origin: Location,
Gavin Wood's avatar
Gavin Wood committed
	trader: Config::Trader,
	/// The most recent error result and instruction index into the fragment in which it occurred,
Gavin Wood's avatar
Gavin Wood committed
	error: Option<(u32, XcmError)>,
	/// The surplus weight, defined as the amount by which `max_weight` is
	/// an over-estimate of the actual weight consumed. We do it this way to avoid needing the
	/// execution engine to keep track of all instructions' weights (it only needs to care about
	/// the weight of dynamically determined instructions such as `Transact`).
Gavin Wood's avatar
Gavin Wood committed
	total_surplus: Weight,
	total_refunded: Weight,
	error_handler: Xcm<Config::RuntimeCall>,
	error_handler_weight: Weight,
	appendix: Xcm<Config::RuntimeCall>,
	appendix_weight: Weight,
	transact_status: MaybeErrorCode,
	fees_mode: FeesMode,
Gavin Wood's avatar
Gavin Wood committed
#[cfg(feature = "runtime-benchmarks")]
impl<Config: config::Config> XcmExecutor<Config> {
Francisco Aguirre's avatar
Francisco Aguirre committed
	pub fn holding(&self) -> &AssetsInHolding {
Gavin Wood's avatar
Gavin Wood committed
		&self.holding
	}
Francisco Aguirre's avatar
Francisco Aguirre committed
	pub fn set_holding(&mut self, v: AssetsInHolding) {
Gavin Wood's avatar
Gavin Wood committed
		self.holding = v
	}
	pub fn holding_limit(&self) -> &usize {
		&self.holding_limit
	}
	pub fn set_holding_limit(&mut self, v: usize) {
		self.holding_limit = v
	}
Francisco Aguirre's avatar
Francisco Aguirre committed
	pub fn origin(&self) -> &Option<Location> {
Gavin Wood's avatar
Gavin Wood committed
		&self.context.origin
	}
Francisco Aguirre's avatar
Francisco Aguirre committed
	pub fn set_origin(&mut self, v: Option<Location>) {
Gavin Wood's avatar
Gavin Wood committed
		self.context.origin = v
	}
Francisco Aguirre's avatar
Francisco Aguirre committed
	pub fn original_origin(&self) -> &Location {
Gavin Wood's avatar
Gavin Wood committed
		&self.original_origin
	}
Francisco Aguirre's avatar
Francisco Aguirre committed
	pub fn set_original_origin(&mut self, v: Location) {
Gavin Wood's avatar
Gavin Wood committed
		self.original_origin = v
	}
	pub fn trader(&self) -> &Config::Trader {
		&self.trader
	}
	pub fn set_trader(&mut self, v: Config::Trader) {
		self.trader = v
	}
	pub fn error(&self) -> &Option<(u32, XcmError)> {
		&self.error
	}
	pub fn set_error(&mut self, v: Option<(u32, XcmError)>) {
		self.error = v
	}
	pub fn total_surplus(&self) -> &Weight {
		&self.total_surplus
	}
	pub fn set_total_surplus(&mut self, v: Weight) {
		self.total_surplus = v
	}
	pub fn total_refunded(&self) -> &Weight {
		&self.total_refunded
	}
	pub fn set_total_refunded(&mut self, v: Weight) {
		self.total_refunded = v
	}
	pub fn error_handler(&self) -> &Xcm<Config::RuntimeCall> {
		&self.error_handler
	}
	pub fn set_error_handler(&mut self, v: Xcm<Config::RuntimeCall>) {
		self.error_handler = v
	}
	pub fn error_handler_weight(&self) -> &Weight {
		&self.error_handler_weight
	}
	pub fn set_error_handler_weight(&mut self, v: Weight) {
		self.error_handler_weight = v
	}
	pub fn appendix(&self) -> &Xcm<Config::RuntimeCall> {
		&self.appendix
	}
	pub fn set_appendix(&mut self, v: Xcm<Config::RuntimeCall>) {
		self.appendix = v
	}
	pub fn appendix_weight(&self) -> &Weight {
		&self.appendix_weight
	}
	pub fn set_appendix_weight(&mut self, v: Weight) {
		self.appendix_weight = v
	}
	pub fn transact_status(&self) -> &MaybeErrorCode {
		&self.transact_status
	}
	pub fn set_transact_status(&mut self, v: MaybeErrorCode) {
		self.transact_status = v
	}
	pub fn fees_mode(&self) -> &FeesMode {
		&self.fees_mode
	}
	pub fn set_fees_mode(&mut self, v: FeesMode) {
		self.fees_mode = v
	}
	pub fn topic(&self) -> &Option<[u8; 32]> {
		&self.context.topic
	}
	pub fn set_topic(&mut self, v: Option<[u8; 32]>) {
		self.context.topic = v;
	}
}

pub struct WeighedMessage<Call>(Weight, Xcm<Call>);
impl<C> PreparedMessage for WeighedMessage<C> {
	fn weight_of(&self) -> Weight {
		self.0
	}
}
impl<Config: config::Config> ExecuteXcm<Config::RuntimeCall> for XcmExecutor<Config> {
Gavin Wood's avatar
Gavin Wood committed
	type Prepared = WeighedMessage<Config::RuntimeCall>;
	fn prepare(
		mut message: Xcm<Config::RuntimeCall>,
Gavin Wood's avatar
Gavin Wood committed
	) -> Result<Self::Prepared, Xcm<Config::RuntimeCall>> {
		match Config::Weigher::weight(&mut message) {
			Ok(weight) => Ok(WeighedMessage(weight, message)),
			Err(_) => Err(message),
		}
	}
	fn execute(
Francisco Aguirre's avatar
Francisco Aguirre committed
		origin: impl Into<Location>,
Gavin Wood's avatar
Gavin Wood committed
		WeighedMessage(xcm_weight, mut message): WeighedMessage<Config::RuntimeCall>,
		id: &mut XcmHash,
		weight_credit: Weight,
	) -> Outcome {
		log::trace!(
Loading full blame...