mod.rs 53.3 KiB
Newer Older
Francisco Aguirre's avatar
Francisco Aguirre committed
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Polkadot.

// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.

//! Version 4 of the Cross-Consensus Message format data structures.

pub use super::v2::GetWeight;
use super::v3::{
	Instruction as OldInstruction, PalletInfo as OldPalletInfo,
	QueryResponseInfo as OldQueryResponseInfo, Response as OldResponse, Xcm as OldXcm,
};
use crate::DoubleEncoded;
use alloc::{vec, vec::Vec};
use bounded_collections::{parameter_types, BoundedVec};
use core::{
	convert::{TryFrom, TryInto},
	fmt::Debug,
	result,
};
use derivative::Derivative;
use parity_scale_codec::{
	self, decode_vec_with_len, Compact, Decode, Encode, Error as CodecError, Input as CodecInput,
	MaxEncodedLen,
};
Francisco Aguirre's avatar
Francisco Aguirre committed
use scale_info::TypeInfo;

mod asset;
mod junction;
pub(crate) mod junctions;
mod location;
mod traits;

pub use asset::{
	Asset, AssetFilter, AssetId, AssetInstance, Assets, Fungibility, WildAsset, WildFungibility,
	MAX_ITEMS_IN_ASSETS,
};
pub use junction::{BodyId, BodyPart, Junction, NetworkId};
pub use junctions::Junctions;
pub use location::{Ancestor, AncestorThen, InteriorLocation, Location, Parent, ParentThen};
pub use traits::{
	send_xcm, validate_send, Error, ExecuteXcm, Outcome, PreparedMessage, Reanchorable, Result,
	SendError, SendResult, SendXcm, Weight, XcmHash,
};
// These parts of XCM v3 are unchanged in XCM v4, and are re-imported here.
pub use super::v3::{MaybeErrorCode, OriginKind, WeightLimit};

/// This module's XCM version.
pub const VERSION: super::Version = 4;

/// An identifier for a query.
pub type QueryId = u64;

#[derive(Derivative, Default, Encode, TypeInfo)]
Francisco Aguirre's avatar
Francisco Aguirre committed
#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
#[codec(encode_bound())]
#[codec(decode_bound())]
#[scale_info(bounds(), skip_type_params(Call))]
pub struct Xcm<Call>(pub Vec<Instruction<Call>>);

pub const MAX_INSTRUCTIONS_TO_DECODE: u8 = 100;

environmental::environmental!(instructions_count: u8);

impl<Call> Decode for Xcm<Call> {
	fn decode<I: CodecInput>(input: &mut I) -> core::result::Result<Self, CodecError> {
		instructions_count::using_once(&mut 0, || {
			let number_of_instructions: u32 = <Compact<u32>>::decode(input)?.into();
			instructions_count::with(|count| {
				*count = count.saturating_add(number_of_instructions as u8);
				if *count > MAX_INSTRUCTIONS_TO_DECODE {
					return Err(CodecError::from("Max instructions exceeded"))
				}
				Ok(())
			})
			.expect("Called in `using` context and thus can not return `None`; qed")?;
			let decoded_instructions = decode_vec_with_len(input, number_of_instructions as usize)?;
			Ok(Self(decoded_instructions))
		})
	}
}

Francisco Aguirre's avatar
Francisco Aguirre committed
impl<Call> Xcm<Call> {
	/// Create an empty instance.
	pub fn new() -> Self {
		Self(vec![])
	}

	/// Return `true` if no instructions are held in `self`.
	pub fn is_empty(&self) -> bool {
		self.0.is_empty()
	}

	/// Return the number of instructions held in `self`.
	pub fn len(&self) -> usize {
		self.0.len()
	}

	/// Return a reference to the inner value.
	pub fn inner(&self) -> &[Instruction<Call>] {
		&self.0
	}

	/// Return a mutable reference to the inner value.
	pub fn inner_mut(&mut self) -> &mut Vec<Instruction<Call>> {
		&mut self.0
	}

	/// Consume and return the inner value.
	pub fn into_inner(self) -> Vec<Instruction<Call>> {
		self.0
	}

	/// Return an iterator over references to the items.
	pub fn iter(&self) -> impl Iterator<Item = &Instruction<Call>> {
		self.0.iter()
	}

	/// Return an iterator over mutable references to the items.
	pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Instruction<Call>> {
		self.0.iter_mut()
	}

	/// Consume and return an iterator over the items.
	pub fn into_iter(self) -> impl Iterator<Item = Instruction<Call>> {
		self.0.into_iter()
	}

	/// Consume and either return `self` if it contains some instructions, or if it's empty, then
	/// instead return the result of `f`.
	pub fn or_else(self, f: impl FnOnce() -> Self) -> Self {
		if self.0.is_empty() {
			f()
		} else {
			self
		}
	}

	/// Return the first instruction, if any.
	pub fn first(&self) -> Option<&Instruction<Call>> {
		self.0.first()
	}

	/// Return the last instruction, if any.
	pub fn last(&self) -> Option<&Instruction<Call>> {
		self.0.last()
	}

	/// Return the only instruction, contained in `Self`, iff only one exists (`None` otherwise).
	pub fn only(&self) -> Option<&Instruction<Call>> {
		if self.0.len() == 1 {
			self.0.first()
		} else {
			None
		}
	}

	/// Return the only instruction, contained in `Self`, iff only one exists (returns `self`
	/// otherwise).
	pub fn into_only(mut self) -> core::result::Result<Instruction<Call>, Self> {
		if self.0.len() == 1 {
			self.0.pop().ok_or(self)
		} else {
			Err(self)
		}
	}
}

impl<Call> From<Vec<Instruction<Call>>> for Xcm<Call> {
	fn from(c: Vec<Instruction<Call>>) -> Self {
		Self(c)
	}
}

impl<Call> From<Xcm<Call>> for Vec<Instruction<Call>> {
	fn from(c: Xcm<Call>) -> Self {
		c.0
	}
}

/// A prelude for importing all types typically used when interacting with XCM messages.
pub mod prelude {
	mod contents {
		pub use super::super::{
			send_xcm, validate_send, Ancestor, AncestorThen, Asset,
			AssetFilter::{self, *},
			AssetId,
			AssetInstance::{self, *},
			Assets, BodyId, BodyPart, Error as XcmError, ExecuteXcm,
Loading full blame...