lib.rs 113 KiB
Newer Older
Gavin Wood's avatar
Gavin Wood committed
							}
Francisco Aguirre's avatar
Francisco Aguirre committed
							let dispatch_origin = Origin::Response(origin.clone()).into();
Gavin Wood's avatar
Gavin Wood committed
							match call.dispatch(dispatch_origin) {
								Ok(post_info) => {
									let e = Event::Notified { query_id, pallet_index, call_index };
Gavin Wood's avatar
Gavin Wood committed
									Self::deposit_event(e);
									post_info.actual_weight
								},
								Err(error_and_info) => {
									let e = Event::NotifyDispatchError {
									// Not much to do with the result as it is. It's up to the
									// parachain to ensure that the message makes sense.
Gavin Wood's avatar
Gavin Wood committed
									error_and_info.post_info.actual_weight
								},
Gavin Wood's avatar
Gavin Wood committed
							.unwrap_or(weight)
						} else {
							let e =
								Event::NotifyDecodeFailed { query_id, pallet_index, call_index };
							Self::deposit_event(e);
Gavin Wood's avatar
Gavin Wood committed
							Weight::zero()
						}
					},
					None => {
						let e = Event::ResponseReady { query_id, response: response.clone() };
Gavin Wood's avatar
Gavin Wood committed
						Self::deposit_event(e);
						let at = frame_system::Pallet::<T>::current_block_number();
						let response = response.into();
						Queries::<T>::insert(query_id, QueryStatus::Ready { response, at });
						Weight::zero()
					},
				}
			},
			_ => {
Francisco Aguirre's avatar
Francisco Aguirre committed
				let e = Event::UnexpectedResponse { origin: origin.clone(), query_id };
				Self::deposit_event(e);
Gavin Wood's avatar
Gavin Wood committed
				Weight::zero()
			},
impl<T: Config> CheckSuspension for Pallet<T> {
	fn is_suspended<Call>(
Francisco Aguirre's avatar
Francisco Aguirre committed
		_origin: &Location,
		_instructions: &mut [Instruction<Call>],
		_max_weight: Weight,
		_properties: &mut Properties,
	) -> bool {
		XcmExecutionSuspended::<T>::get()
	}
}

/// Ensure that the origin `o` represents an XCM (`Transact`) origin.
///
/// Returns `Ok` with the location of the XCM sender or an `Err` otherwise.
Francisco Aguirre's avatar
Francisco Aguirre committed
pub fn ensure_xcm<OuterOrigin>(o: OuterOrigin) -> Result<Location, BadOrigin>
where
	OuterOrigin: Into<Result<Origin, OuterOrigin>>,
Gavin Wood's avatar
Gavin Wood committed
{
	match o.into() {
		Ok(Origin::Xcm(location)) => Ok(location),
		_ => Err(BadOrigin),
	}
}

/// Ensure that the origin `o` represents an XCM response origin.
///
/// Returns `Ok` with the location of the responder or an `Err` otherwise.
Francisco Aguirre's avatar
Francisco Aguirre committed
pub fn ensure_response<OuterOrigin>(o: OuterOrigin) -> Result<Location, BadOrigin>
where
	OuterOrigin: Into<Result<Origin, OuterOrigin>>,
{
	match o.into() {
		Ok(Origin::Response(location)) => Ok(location),
		_ => Err(BadOrigin),
	}
}

Francisco Aguirre's avatar
Francisco Aguirre committed
/// Filter for `Location` to find those which represent a strict majority approval of an
Gavin Wood's avatar
Gavin Wood committed
///
/// May reasonably be used with `EnsureXcm`.
pub struct IsMajorityOfBody<Prefix, Body>(PhantomData<(Prefix, Body)>);
Francisco Aguirre's avatar
Francisco Aguirre committed
impl<Prefix: Get<Location>, Body: Get<BodyId>> Contains<Location>
	for IsMajorityOfBody<Prefix, Body>
{
Francisco Aguirre's avatar
Francisco Aguirre committed
	fn contains(l: &Location) -> bool {
		let maybe_suffix = l.match_and_split(&Prefix::get());
		matches!(maybe_suffix, Some(Plurality { id, part }) if id == &Body::get() && part.is_majority())
Francisco Aguirre's avatar
Francisco Aguirre committed
/// Filter for `Location` to find those which represent a voice of an identified plurality.
///
/// May reasonably be used with `EnsureXcm`.
pub struct IsVoiceOfBody<Prefix, Body>(PhantomData<(Prefix, Body)>);
Francisco Aguirre's avatar
Francisco Aguirre committed
impl<Prefix: Get<Location>, Body: Get<BodyId>> Contains<Location> for IsVoiceOfBody<Prefix, Body> {
	fn contains(l: &Location) -> bool {
		let maybe_suffix = l.match_and_split(&Prefix::get());
		matches!(maybe_suffix, Some(Plurality { id, part }) if id == &Body::get() && part == &BodyPart::Voice)
	}
}

Francisco Aguirre's avatar
Francisco Aguirre committed
/// `EnsureOrigin` implementation succeeding with a `Location` value to recognize and filter
Francisco Aguirre's avatar
Francisco Aguirre committed
pub struct EnsureXcm<F, L = Location>(PhantomData<(F, L)>);
impl<
		O: OriginTrait + From<Origin>,
		F: Contains<L>,
		L: TryFrom<Location> + TryInto<Location> + Clone,
	> EnsureOrigin<O> for EnsureXcm<F, L>
where
	O::PalletsOrigin: From<Origin> + TryInto<Origin, Error = O::PalletsOrigin>,
Francisco Aguirre's avatar
Francisco Aguirre committed
	type Success = L;
Gavin Wood's avatar
Gavin Wood committed

	fn try_origin(outer: O) -> Result<Self::Success, O> {
		outer.try_with_caller(|caller| {
			caller.try_into().and_then(|o| match o {
Francisco Aguirre's avatar
Francisco Aguirre committed
				Origin::Xcm(ref location)
					if F::contains(&location.clone().try_into().map_err(|_| o.clone().into())?) =>
					Ok(location.clone().try_into().map_err(|_| o.clone().into())?),
				Origin::Xcm(location) => Err(Origin::Xcm(location).into()),
				o => Err(o.into()),
Gavin Wood's avatar
Gavin Wood committed
	}

	#[cfg(feature = "runtime-benchmarks")]
	fn try_successful_origin() -> Result<O, ()> {
		Ok(O::from(Origin::Xcm(Here.into())))
Francisco Aguirre's avatar
Francisco Aguirre committed
/// `EnsureOrigin` implementation succeeding with a `Location` value to recognize and filter
/// the `Origin::Response` item.
pub struct EnsureResponse<F>(PhantomData<F>);
Francisco Aguirre's avatar
Francisco Aguirre committed
impl<O: OriginTrait + From<Origin>, F: Contains<Location>> EnsureOrigin<O> for EnsureResponse<F>
where
	O::PalletsOrigin: From<Origin> + TryInto<Origin, Error = O::PalletsOrigin>,
{
Francisco Aguirre's avatar
Francisco Aguirre committed
	type Success = Location;

	fn try_origin(outer: O) -> Result<Self::Success, O> {
		outer.try_with_caller(|caller| {
			caller.try_into().and_then(|o| match o {
				Origin::Response(responder) => Ok(responder),
				o => Err(o.into()),
			})
		})
	}

	#[cfg(feature = "runtime-benchmarks")]
	fn try_successful_origin() -> Result<O, ()> {
		Ok(O::from(Origin::Response(Here.into())))
Francisco Aguirre's avatar
Francisco Aguirre committed
/// A simple passthrough where we reuse the `Location`-typed XCM origin as the inner value of
/// this crate's `Origin::Xcm` value.
Sergej Sakac's avatar
Sergej Sakac committed
pub struct XcmPassthrough<RuntimeOrigin>(PhantomData<RuntimeOrigin>);
impl<RuntimeOrigin: From<crate::Origin>> ConvertOrigin<RuntimeOrigin>
	for XcmPassthrough<RuntimeOrigin>
{
Francisco Aguirre's avatar
Francisco Aguirre committed
		origin: impl Into<Location>,
Francisco Aguirre's avatar
Francisco Aguirre committed
	) -> Result<RuntimeOrigin, Location> {
		match kind {
			OriginKind::Xcm => Ok(crate::Origin::Xcm(origin).into()),
			_ => Err(origin),