// Copyright (C) Parity Technologies (UK) Ltd. and Dijital Kurdistan Tech Institute // This file is part of Pezkuwi. // Pezkuwi 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. // Pezkuwi 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 Pezkuwi. If not, see . use crate::{Junctions::Here, Xcm}; use codec::{Decode, Encode}; use core::{fmt::Debug, result}; use pezframe_support::{parameter_types, pezpallet_prelude::Get}; use pezsp_arithmetic::traits::Zero; use xcm::latest::{ Error as XcmError, InteriorLocation, Location, QueryId, Response, Result as XcmResult, Weight, XcmContext, }; /// Define what needs to be done upon receiving a query response. pub trait OnResponse { /// Returns `true` if we are expecting a response from `origin` for query `query_id` that was /// queried by `querier`. fn expecting_response(origin: &Location, query_id: u64, querier: Option<&Location>) -> bool; /// Handler for receiving a `response` from `origin` relating to `query_id` initiated by /// `querier`. fn on_response( origin: &Location, query_id: u64, querier: Option<&Location>, response: Response, max_weight: Weight, context: &XcmContext, ) -> Weight; } impl OnResponse for () { fn expecting_response(_origin: &Location, _query_id: u64, _querier: Option<&Location>) -> bool { false } fn on_response( _origin: &Location, _query_id: u64, _querier: Option<&Location>, _response: Response, _max_weight: Weight, _context: &XcmContext, ) -> Weight { Weight::zero() } } /// Trait for a type which handles notifying a destination of XCM version changes. pub trait VersionChangeNotifier { /// Start notifying `location` should the XCM version of this chain change. /// /// When it does, this type should ensure a `QueryResponse` message is sent with the given /// `query_id` & `max_weight` and with a `response` of `Response::Version`. This should happen /// until/unless `stop` is called with the correct `query_id`. /// /// If the `location` has an ongoing notification and when this function is called, then an /// error should be returned. fn start( location: &Location, query_id: QueryId, max_weight: Weight, context: &XcmContext, ) -> XcmResult; /// Stop notifying `location` should the XCM change. Returns an error if there is no existing /// notification set up. fn stop(location: &Location, context: &XcmContext) -> XcmResult; /// Return true if a location is subscribed to XCM version changes. fn is_subscribed(location: &Location) -> bool; } impl VersionChangeNotifier for () { fn start(_: &Location, _: QueryId, _: Weight, _: &XcmContext) -> XcmResult { Err(XcmError::Unimplemented) } fn stop(_: &Location, _: &XcmContext) -> XcmResult { Err(XcmError::Unimplemented) } fn is_subscribed(_: &Location) -> bool { false } } /// The possible state of an XCM query response. #[derive(Debug, PartialEq, Eq, Encode, Decode)] pub enum QueryResponseStatus { /// The response has arrived, and includes the inner Response and the block number it arrived /// at. Ready { response: Response, at: BlockNumber }, /// The response has not yet arrived, the XCM might still be executing or the response might be /// in transit. Pending { timeout: BlockNumber }, /// No response with the given `QueryId` was found, or the response was already queried and /// removed from local storage. NotFound, /// Got an unexpected XCM version. UnexpectedVersion, } /// Provides methods to expect responses from XCMs and query their status. pub trait QueryHandler { type BlockNumber: Zero + Encode; type Error; type UniversalLocation: Get; /// Attempt to create a new query ID and register it as a query that is yet to respond. fn new_query( responder: impl Into, timeout: Self::BlockNumber, match_querier: impl Into, ) -> QueryId; /// Consume `message` and return another which is equivalent to it except that it reports /// back the outcome. /// /// - `message`: The message whose outcome should be reported. /// - `responder`: The origin from which a response should be expected. /// - `timeout`: The block number after which it is permissible to return `NotFound` from /// `take_response`. /// /// `report_outcome` may return an error if the `responder` is not invertible. /// /// It is assumed that the querier of the response will be `Here`. /// The response can be queried with `take_response`. fn report_outcome( message: &mut Xcm<()>, responder: impl Into, timeout: Self::BlockNumber, ) -> result::Result; /// Attempt to remove and return the response of query with ID `query_id`. fn take_response(id: QueryId) -> QueryResponseStatus; /// Makes sure to expect a response with the given id. #[cfg(feature = "runtime-benchmarks")] fn expect_response(id: QueryId, response: Response); } parameter_types! { pub UniversalLocation: InteriorLocation = Here; } impl QueryHandler for () { type BlockNumber = u64; type Error = (); type UniversalLocation = UniversalLocation; fn take_response(_query_id: QueryId) -> QueryResponseStatus { QueryResponseStatus::NotFound } fn new_query( _responder: impl Into, _timeout: Self::BlockNumber, _match_querier: impl Into, ) -> QueryId { 0u64 } fn report_outcome( _message: &mut Xcm<()>, _responder: impl Into, _timeout: Self::BlockNumber, ) -> Result { Err(()) } #[cfg(feature = "runtime-benchmarks")] fn expect_response(_id: QueryId, _response: crate::Response) {} }