Skip to content
lib.rs 79.1 KiB
Newer Older
Gavin Wood's avatar
Gavin Wood committed
					if querier.map_or(true, |q| q != &match_querier) {
						Self::deposit_event(Event::InvalidQuerier(
							*origin,
Gavin Wood's avatar
Gavin Wood committed
							match_querier,
							querier.cloned(),
Gavin Wood's avatar
Gavin Wood committed
						return Weight::zero()
Gavin Wood's avatar
Gavin Wood committed
				}
				let responder = match MultiLocation::try_from(responder) {
					Ok(r) => r,
					Err(_) => {
						Self::deposit_event(Event::InvalidResponderVersion(*origin, query_id));
						return Weight::zero()
					},
				};
				if origin != &responder {
					Self::deposit_event(Event::InvalidResponder(
						*origin,
						query_id,
						Some(responder),
					));
					return Weight::zero()
				}
				return match maybe_notify {
					Some((pallet_index, call_index)) => {
						// This is a bit horrible, but we happen to know that the `Call` will
						// be built by `(pallet_index: u8, call_index: u8, QueryId, Response)`.
						// So we just encode that and then re-encode to a real Call.
						let bare = (pallet_index, call_index, query_id, response);
						if let Ok(call) = bare.using_encoded(|mut bytes| {
							<T as Config>::RuntimeCall::decode(&mut bytes)
						}) {
							Queries::<T>::remove(query_id);
							let weight = call.get_dispatch_info().weight;
							if weight.any_gt(max_weight) {
								let e = Event::NotifyOverweight(
									query_id,
									pallet_index,
									call_index,
									weight,
									max_weight,
								);
								Self::deposit_event(e);
								return Weight::zero()
							}
							let dispatch_origin = Origin::Response(*origin).into();
							match call.dispatch(dispatch_origin) {
								Ok(post_info) => {
									let e = Event::Notified(query_id, pallet_index, call_index);
									Self::deposit_event(e);
									post_info.actual_weight
								},
								Err(error_and_info) => {
									let e = Event::NotifyDispatchError(
										query_id,
										pallet_index,
										call_index,
									);
									Self::deposit_event(e);
Gavin Wood's avatar
Gavin Wood committed
									// Not much to do with the result as it is. It's up to the parachain to ensure that the
									// message makes sense.
									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.clone());
						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()
					},
				}
			},
			_ => {
				Self::deposit_event(Event::UnexpectedResponse(*origin, query_id));
				Weight::zero()
			},
impl<T: Config> CheckSuspension for Pallet<T> {
	fn is_suspended<Call>(
		_origin: &MultiLocation,
		_instructions: &mut [Instruction<Call>],
		_max_weight: Weight,
		_weight_credit: &mut Weight,
	) -> 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.
Gavin Wood's avatar
Gavin Wood committed
pub fn ensure_xcm<OuterOrigin>(o: OuterOrigin) -> Result<MultiLocation, 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.
pub fn ensure_response<OuterOrigin>(o: OuterOrigin) -> Result<MultiLocation, BadOrigin>
where
	OuterOrigin: Into<Result<Origin, OuterOrigin>>,
{
	match o.into() {
		Ok(Origin::Response(location)) => Ok(location),
		_ => Err(BadOrigin),
	}
}

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

/// `EnsureOrigin` implementation succeeding with a `MultiLocation` value to recognize and filter the
Gavin Wood's avatar
Gavin Wood committed
/// `Origin::Xcm` item.
pub struct EnsureXcm<F>(PhantomData<F>);
impl<O: OriginTrait + From<Origin>, F: Contains<MultiLocation>> EnsureOrigin<O> for EnsureXcm<F>
where
	O::PalletsOrigin: From<Origin> + TryInto<Origin, Error = O::PalletsOrigin>,
Gavin Wood's avatar
Gavin Wood committed
{
	type Success = MultiLocation;

	fn try_origin(outer: O) -> Result<Self::Success, O> {
		outer.try_with_caller(|caller| {
			caller.try_into().and_then(|o| match o {
				Origin::Xcm(location) if F::contains(&location) => Ok(location),
				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())))
/// `EnsureOrigin` implementation succeeding with a `MultiLocation` value to recognize and filter
/// the `Origin::Response` item.
pub struct EnsureResponse<F>(PhantomData<F>);
impl<O: OriginTrait + From<Origin>, F: Contains<MultiLocation>> EnsureOrigin<O>
	for EnsureResponse<F>
where
	O::PalletsOrigin: From<Origin> + TryInto<Origin, Error = O::PalletsOrigin>,
{
	type Success = MultiLocation;

	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())))
/// A simple passthrough where we reuse the `MultiLocation`-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>
{
	fn convert_origin(
		origin: impl Into<MultiLocation>,
		kind: OriginKind,
Sergej Sakac's avatar
Sergej Sakac committed
	) -> Result<RuntimeOrigin, MultiLocation> {
		match kind {
			OriginKind::Xcm => Ok(crate::Origin::Xcm(origin).into()),
			_ => Err(origin),