Skip to content

Commit

Permalink
Add pallet_xcm::execute
Browse files Browse the repository at this point in the history
  • Loading branch information
pgherveou committed Aug 29, 2023
1 parent 0f9a71c commit 3ce5389
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 1 deletion.
7 changes: 7 additions & 0 deletions substrate/frame/contracts/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ sp-io = { path = "../../primitives/io", default-features = false}
sp-runtime = { path = "../../primitives/runtime", default-features = false}
sp-std = { path = "../../primitives/std", default-features = false}

xcm = { path = "../../../polkadot/xcm", default-features = false}
xcm-executor = { path = "../../../polkadot/xcm/xcm-executor", default-features = false}
pallet-xcm = { path = "../../../polkadot/xcm/pallet-xcm", default-features = false}

[dev-dependencies]
array-bytes = "6.1"
assert_matches = "1"
Expand Down Expand Up @@ -90,6 +94,9 @@ std = [
"sp-std/std",
"wasm-instrument/std",
"wasmi/std",
"pallet-xcm/std",
"xcm/std",
"xcm-executor/std",
]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
Expand Down
19 changes: 19 additions & 0 deletions substrate/frame/contracts/src/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ use sp_core::{
use sp_io::{crypto::secp256k1_ecdsa_recover_compressed, hashing::blake2_256};
use sp_runtime::traits::{Convert, Hash, Zero};
use sp_std::{marker::PhantomData, mem, prelude::*, vec::Vec};
use xcm::VersionedXcm;

pub type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
pub type MomentOf<T> = <<T as Config>::Time as Time>::Moment;
Expand All @@ -61,6 +62,8 @@ pub type TopicOf<T> = <T as frame_system::Config>::Hash;
/// Type for variable sized storage key. Used for transparent hashing.
type VarSizedKey<T> = BoundedVec<u8, <T as Config>::MaxStorageKeyLen>;

pub type CallOf<T> = <T as frame_system::Config>::RuntimeCall;

/// Combined key type for both fixed and variable sized storage keys.
pub enum Key<T: Config> {
/// Variant for fixed sized keys.
Expand Down Expand Up @@ -345,6 +348,13 @@ pub trait Ext: sealing::Sealed {
&mut self,
code_hash: &CodeHash<Self::T>,
) -> Result<(), DispatchError>;

/// Execute an XCM message locally, using the contract's address as the origin.
fn xcm_execute(
&mut self,
message: VersionedXcm<CallOf<Self::T>>,
max_weight: Weight,
) -> DispatchResultWithPostInfo;
}

/// Describes the different functions that can be exported by an [`Executable`].
Expand Down Expand Up @@ -1446,6 +1456,15 @@ where
call.dispatch(origin)
}

fn xcm_execute(
&mut self,
message: VersionedXcm<CallOf<T>>,
max_weight: Weight,
) -> DispatchResultWithPostInfo {
let origin = RawOrigin::Signed(self.address().clone()).into();
pallet_xcm::Pallet::<T>::execute(origin, Box::new(message), max_weight)
}

fn ecdsa_recover(&self, signature: &[u8; 65], message_hash: &[u8; 32]) -> Result<[u8; 33], ()> {
secp256k1_ecdsa_recover_compressed(signature, message_hash).map_err(|_| ())
}
Expand Down
2 changes: 1 addition & 1 deletion substrate/frame/contracts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ pub mod pallet {
pub struct Pallet<T>(_);

#[pallet::config]
pub trait Config: frame_system::Config {
pub trait Config: frame_system::Config + pallet_xcm::Config {
/// The time implementation used to supply timestamps to contracts through `seal_now`.
type Time: Time;

Expand Down
42 changes: 42 additions & 0 deletions substrate/frame/contracts/src/wasm/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ pub enum ReturnCode {
EcdsaRecoverFailed = 11,
/// sr25519 signature verification failed.
Sr25519VerifyFailed = 12,
/// The `seal_xcm_execute` was executed but returned an error.
XcmExcuteFailed = 13,
}

impl From<ExecReturnValue> for ReturnCode {
Expand Down Expand Up @@ -260,6 +262,8 @@ pub enum RuntimeCosts {
ChainExtension(Weight),
/// Weight charged for calling into the runtime.
CallRuntime(Weight),
/// Weight charged for Executing an XCM message.
XcmExecute(Weight),
/// Weight of calling `seal_set_code_hash`
SetCodeHash,
/// Weight of calling `ecdsa_to_eth_address`
Expand Down Expand Up @@ -350,6 +354,7 @@ impl RuntimeCosts {
.saturating_add(s.sr25519_verify_per_byte.saturating_mul(len.into())),
ChainExtension(weight) => weight,
CallRuntime(weight) => weight,
XcmExecute(weight) => weight,
SetCodeHash => s.set_code_hash,
EcdsaToEthAddress => s.ecdsa_to_eth_address,
ReentrantCount => s.reentrance_count,
Expand Down Expand Up @@ -2626,6 +2631,43 @@ pub mod env {
}
}

fn xcm_execute(
ctx: _,
memory: _,
call_ptr: u32,
call_len: u32,
max_weight_ptr: u32,
) -> Result<ReturnCode, TrapReason> {
use crate::exec::CallOf;
use frame_support::dispatch::{extract_actual_weight, DispatchInfo};
use pallet_xcm::WeightInfo;
use xcm::VersionedXcm;

ctx.charge_gas(RuntimeCosts::CopyFromContract(call_len))?;
let message: VersionedXcm<CallOf<E::T>> =
ctx.read_sandbox_memory_as_unbounded(memory, call_ptr, call_len)?;
let max_weight: Weight = ctx.read_sandbox_memory_as(memory, max_weight_ptr)?;

let weight = max_weight.saturating_add(<E::T as pallet_xcm::Config>::WeightInfo::execute());
let dispatch_info = DispatchInfo { weight, ..Default::default() };

let charged = ctx.charge_gas(RuntimeCosts::XcmExecute(weight))?;
let result = ctx.ext.xcm_execute(message, max_weight);

let actual_weight = extract_actual_weight(&result, &dispatch_info);
ctx.adjust_gas(charged, RuntimeCosts::XcmExecute(actual_weight));
match result {
Ok(_) => Ok(ReturnCode::Success),
Err(e) => {
if ctx.ext.append_debug_buffer("") {
ctx.ext.append_debug_buffer("seal0::xcm_execute failed with: ");
ctx.ext.append_debug_buffer(e.into());
};
Ok(ReturnCode::XcmExcuteFailed)
},
}
}

/// Recovers the ECDSA public key from the given message hash and signature.
///
/// Writes the public key into the given output buffer.
Expand Down

0 comments on commit 3ce5389

Please sign in to comment.