diff --git a/polkadot/xcm/xcm-executor/src/traits/on_response.rs b/polkadot/xcm/xcm-executor/src/traits/on_response.rs index 3558160dc87d..ec15053e4482 100644 --- a/polkadot/xcm/xcm-executor/src/traits/on_response.rs +++ b/polkadot/xcm/xcm-executor/src/traits/on_response.rs @@ -16,8 +16,11 @@ use crate::Xcm; use core::result; -use frame_support::pallet_prelude::{Get, TypeInfo}; -use parity_scale_codec::{FullCodec, MaxEncodedLen}; +use frame_support::{ + dispatch::fmt::Debug, + pallet_prelude::{Get, TypeInfo}, +}; +use parity_scale_codec::{Decode, Encode, FullCodec, MaxEncodedLen}; use sp_arithmetic::traits::Zero; use sp_std::fmt::Debug; use xcm::latest::{ @@ -103,7 +106,7 @@ impl VersionChangeNotifier for () { } /// The possible state of an XCM query response. -#[derive(Debug, PartialEq, Eq)] +#[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. diff --git a/substrate/frame/contracts/src/exec.rs b/substrate/frame/contracts/src/exec.rs index abe56add3c43..519f23f84251 100644 --- a/substrate/frame/contracts/src/exec.rs +++ b/substrate/frame/contracts/src/exec.rs @@ -45,12 +45,10 @@ use sp_core::{ Get, }; use sp_io::{crypto::secp256k1_ecdsa_recover_compressed, hashing::blake2_256}; -use sp_runtime::{ - traits::{Convert, Dispatchable, Hash, Zero}, - DispatchError, -}; -use sp_std::{fmt::Debug, marker::PhantomData, mem, prelude::*, vec::Vec}; -use xcm::{VersionedMultiLocation, VersionedXcm}; +use sp_runtime::traits::{Convert, Hash, Zero}; +use sp_std::{marker::PhantomData, mem, prelude::*, vec::Vec}; +use xcm::{v3::MultiLocation, VersionedMultiLocation, VersionedXcm}; +use xcm_executor::traits::{QueryHandler, QueryResponseStatus}; pub type AccountIdOf = ::AccountId; pub type MomentOf = <::Time as Time>::Moment; @@ -358,6 +356,17 @@ pub trait Ext: sealing::Sealed { ) -> DispatchResultWithPostInfo; fn xcm_send(&self, dest: VersionedMultiLocation, msg: VersionedXcm<()>) -> DispatchResult; + + fn xcm_query( + &self, + timeout: BlockNumberFor, + match_querier: VersionedMultiLocation, + ) -> Result< as QueryHandler>::QueryId, DispatchError>; + + fn xcm_take_response( + &self, + query_id: as QueryHandler>::QueryId, + ) -> QueryResponseStatus>; } /// Describes the different functions that can be exported by an [`Executable`]. @@ -1473,6 +1482,33 @@ where pallet_xcm::Pallet::::send(origin, Box::new(dest), Box::new(msg)) } + fn xcm_query( + &self, + timeout: BlockNumberFor, + match_querier: VersionedMultiLocation, + ) -> Result< as QueryHandler>::QueryId, DispatchError> { + use frame_support::traits::EnsureOrigin; + + let origin = RawOrigin::Signed(self.address().clone()).into(); + let responder = ::ExecuteXcmOrigin::ensure_origin(origin)?; + + let query_id = as QueryHandler>::new_query( + responder, + timeout.into(), + MultiLocation::try_from(match_querier) + .map_err(|_| Into::::into(pallet_xcm::Error::::BadVersion))?, + ); + + Ok(query_id) + } + + fn xcm_take_response( + &self, + query_id: as QueryHandler>::QueryId, + ) -> QueryResponseStatus> { + as QueryHandler>::take_response(query_id) + } + fn ecdsa_recover(&self, signature: &[u8; 65], message_hash: &[u8; 32]) -> Result<[u8; 33], ()> { secp256k1_ecdsa_recover_compressed(signature, message_hash).map_err(|_| ()) } diff --git a/substrate/frame/contracts/src/wasm/runtime.rs b/substrate/frame/contracts/src/wasm/runtime.rs index b18ae0352b2a..1a5a4bdf0495 100644 --- a/substrate/frame/contracts/src/wasm/runtime.rs +++ b/substrate/frame/contracts/src/wasm/runtime.rs @@ -2695,6 +2695,52 @@ pub mod env { } } + fn xcm_query( + ctx: _, + memory: _, + timeout_ptr: u32, + match_querier_ptr: u32, + output_ptr: u32, + ) -> Result { + use frame_system::pallet_prelude::BlockNumberFor; + use xcm::VersionedMultiLocation; + + let timeout: BlockNumberFor = ctx.read_sandbox_memory_as(memory, timeout_ptr)?; + let match_querier: VersionedMultiLocation = + ctx.read_sandbox_memory_as(memory, match_querier_ptr)?; + // TODO benchmark + match ctx.ext.xcm_query(timeout, match_querier) { + Ok(query_id) => { + ctx.write_sandbox_memory(memory, output_ptr, &query_id.encode())?; + Ok(ReturnCode::Success) + }, + Err(e) => { + if ctx.ext.append_debug_buffer("") { + ctx.ext.append_debug_buffer("call failed with: "); + ctx.ext.append_debug_buffer(e.into()); + }; + Ok(ReturnCode::CallRuntimeFailed) + }, + } + } + + fn xcm_take_response( + ctx: _, + memory: _, + query_id_ptr: u32, + output_ptr: u32, + ) -> Result { + use xcm_executor::traits::QueryHandler; + + let query_id: as QueryHandler>::QueryId = + ctx.read_sandbox_memory_as(memory, query_id_ptr)?; + + // TODO benchmark + let response = ctx.ext.xcm_take_response(query_id); + ctx.write_sandbox_memory(memory, output_ptr, &response.encode())?; + Ok(ReturnCode::Success) + } + /// Recovers the ECDSA public key from the given message hash and signature. /// /// Writes the public key into the given output buffer.