pallet-xcm: Deprecate execute and send in favor of execute_blob and send_blob (#3749)

`execute` and `send` try to decode the xcm in the parameters before
reaching the filter line.
The new extrinsics decode only after the filter line.
These should be used instead of the old ones.

## TODO
- [x] Tests
- [x] Generate weights
- [x] Deprecation issue ->
https://github.com/paritytech/polkadot-sdk/issues/3771
- [x] PRDoc
- [x] Handle error in pallet-contracts

This would make writing XCMs in PJS Apps more difficult, but here's the
fix for that: https://github.com/polkadot-js/apps/pull/10350.
Already deployed! https://polkadot.js.org/apps/#/utilities/xcm

Supersedes https://github.com/paritytech/polkadot-sdk/pull/1798/

---------

Co-authored-by: PG Herveou <pgherveou@gmail.com>
Co-authored-by: command-bot <>
Co-authored-by: Adrian Catangiu <adrian@parity.io>
This commit is contained in:
Francisco Aguirre
2024-03-27 09:31:01 +01:00
committed by GitHub
parent 66051adb61
commit feee773d15
36 changed files with 1133 additions and 642 deletions
+10 -44
View File
@@ -25,12 +25,8 @@ use crate::{
};
use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen};
use frame_support::{
dispatch::DispatchInfo,
ensure,
pallet_prelude::{DispatchResult, DispatchResultWithPostInfo},
parameter_types,
traits::Get,
weights::Weight,
dispatch::DispatchInfo, ensure, pallet_prelude::DispatchResultWithPostInfo, parameter_types,
traits::Get, weights::Weight,
};
use pallet_contracts_proc_macro::define_env;
use pallet_contracts_uapi::{CallFlags, ReturnFlags};
@@ -41,9 +37,6 @@ use sp_runtime::{
};
use sp_std::{fmt, prelude::*};
use wasmi::{core::HostError, errors::LinkerError, Linker, Memory, Store};
use xcm::VersionedXcm;
type CallOf<T> = <T as frame_system::Config>::RuntimeCall;
/// The maximum nesting depth a contract can use when encoding types.
const MAX_DECODE_NESTING: u32 = 256;
@@ -378,29 +371,6 @@ fn already_charged(_: u32) -> Option<RuntimeCosts> {
None
}
/// Ensure that the XCM program is executable, by checking that it does not contain any [`Transact`]
/// instruction with a call that is not allowed by the CallFilter.
fn ensure_executable<T: Config>(message: &VersionedXcm<CallOf<T>>) -> DispatchResult {
use frame_support::traits::Contains;
use xcm::prelude::{Transact, Xcm};
let mut message: Xcm<CallOf<T>> =
message.clone().try_into().map_err(|_| Error::<T>::XCMDecodeFailed)?;
message.iter_mut().try_for_each(|inst| -> DispatchResult {
let Transact { ref mut call, .. } = inst else { return Ok(()) };
let call = call.ensure_decoded().map_err(|_| Error::<T>::XCMDecodeFailed)?;
if !<T as Config>::CallFilter::contains(call) {
return Err(frame_system::Error::<T>::CallFiltered.into())
}
Ok(())
})?;
Ok(())
}
/// Can only be used for one call.
pub struct Runtime<'a, E: Ext + 'a> {
ext: &'a mut E,
@@ -2112,16 +2082,13 @@ pub mod env {
msg_len: u32,
) -> Result<ReturnErrorCode, TrapReason> {
use frame_support::dispatch::DispatchInfo;
use xcm::VersionedXcm;
use xcm_builder::{ExecuteController, ExecuteControllerWeightInfo};
ctx.charge_gas(RuntimeCosts::CopyFromContract(msg_len))?;
let message: VersionedXcm<CallOf<E::T>> =
ctx.read_sandbox_memory_as_unbounded(memory, msg_ptr, msg_len)?;
ensure_executable::<E::T>(&message)?;
let message = ctx.read_sandbox_memory_as_unbounded(memory, msg_ptr, msg_len)?;
let execute_weight =
<<E::T as Config>::Xcm as ExecuteController<_, _>>::WeightInfo::execute();
<<E::T as Config>::Xcm as ExecuteController<_, _>>::WeightInfo::execute_blob();
let weight = ctx.ext.gas_meter().gas_left().max(execute_weight);
let dispatch_info = DispatchInfo { weight, ..Default::default() };
@@ -2130,9 +2097,9 @@ pub mod env {
RuntimeCosts::CallXcmExecute,
|ctx| {
let origin = crate::RawOrigin::Signed(ctx.ext.address().clone()).into();
let weight_used = <<E::T as Config>::Xcm>::execute(
let weight_used = <<E::T as Config>::Xcm>::execute_blob(
origin,
Box::new(message),
message,
weight.saturating_sub(execute_weight),
)?;
@@ -2152,19 +2119,18 @@ pub mod env {
msg_len: u32,
output_ptr: u32,
) -> Result<ReturnErrorCode, TrapReason> {
use xcm::{VersionedLocation, VersionedXcm};
use xcm::VersionedLocation;
use xcm_builder::{SendController, SendControllerWeightInfo};
ctx.charge_gas(RuntimeCosts::CopyFromContract(msg_len))?;
let dest: VersionedLocation = ctx.read_sandbox_memory_as(memory, dest_ptr)?;
let message: VersionedXcm<()> =
ctx.read_sandbox_memory_as_unbounded(memory, msg_ptr, msg_len)?;
let weight = <<E::T as Config>::Xcm as SendController<_>>::WeightInfo::send();
let message = ctx.read_sandbox_memory_as_unbounded(memory, msg_ptr, msg_len)?;
let weight = <<E::T as Config>::Xcm as SendController<_>>::WeightInfo::send_blob();
ctx.charge_gas(RuntimeCosts::CallRuntime(weight))?;
let origin = crate::RawOrigin::Signed(ctx.ext.address().clone()).into();
match <<E::T as Config>::Xcm>::send(origin, dest.into(), message.into()) {
match <<E::T as Config>::Xcm>::send_blob(origin, dest.into(), message) {
Ok(message_id) => {
ctx.write_sandbox_memory(memory, output_ptr, &message_id.encode())?;
Ok(ReturnErrorCode::Success)