From ab0e1514e2f5dd30b5923c0b3e3e7ab39ffe1612 Mon Sep 17 00:00:00 2001 From: Bryan Chen Date: Thu, 18 Apr 2024 21:52:11 +1200 Subject: [PATCH 1/5] WithMaxSize --- polkadot/xcm/pallet-xcm/src/lib.rs | 26 +++---- polkadot/xcm/xcm-builder/src/controller.rs | 1 + polkadot/xcm/xcm-builder/src/lib.rs | 2 +- substrate/frame/support/src/lib.rs | 2 + substrate/frame/support/src/utils.rs | 91 ++++++++++++++++++++++ 5 files changed, 105 insertions(+), 17 deletions(-) create mode 100644 substrate/frame/support/src/utils.rs diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index cf22b86cf82c..a7102f4035af 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -50,7 +50,7 @@ use sp_runtime::{ use sp_std::{boxed::Box, marker::PhantomData, prelude::*, result::Result, vec}; use xcm::{latest::QueryResponseInfo, prelude::*}; use xcm_builder::{ - ExecuteController, ExecuteControllerWeightInfo, MaxXcmEncodedSize, QueryController, + ExecuteController, ExecuteControllerWeightInfo, MaxXcmEncodedSize, MaxXcmEncodedSizeUsize, QueryController, QueryControllerWeightInfo, SendController, SendControllerWeightInfo, }; use xcm_executor::{ @@ -188,7 +188,7 @@ pub mod pallet { use super::*; use frame_support::{ dispatch::{GetDispatchInfo, PostDispatchInfo}, - parameter_types, + parameter_types, WithMaxSize, }; use frame_system::Config as SysConfig; use sp_core::H256; @@ -942,17 +942,18 @@ pub mod pallet { #[pallet::call(weight(::WeightInfo))] impl Pallet { - /// WARNING: DEPRECATED. `send` will be removed after June 2024. Use `send_blob` instead. - #[allow(deprecated)] - #[deprecated(note = "`send` will be removed after June 2024. Use `send_blob` instead.")] + /// Send an XCM from a local, signed, origin. + /// + /// The destination, `dest`, will receive this message with a `DescendOrigin` instruction + /// that makes the origin of the message be the origin on this system. #[pallet::call_index(0)] pub fn send( origin: OriginFor, dest: Box, - message: Box>, + message: Box, MaxXcmEncodedSizeUsize>>, ) -> DispatchResult { let origin_location = T::SendXcmOrigin::ensure_origin(origin)?; - Self::send_base(origin_location, dest, message)?; + Self::send_base(origin_location, dest, Box::new(message.value()))?; Ok(()) } @@ -1049,22 +1050,15 @@ pub mod pallet { /// No more than `max_weight` will be used in its attempted execution. If this is less than /// the maximum amount of weight that the message could take to be executed, then no /// execution attempt will be made. - /// - /// WARNING: DEPRECATED. `execute` will be removed after June 2024. Use `execute_blob` - /// instead. - #[allow(deprecated)] - #[deprecated( - note = "`execute` will be removed after June 2024. Use `execute_blob` instead." - )] #[pallet::call_index(3)] #[pallet::weight(max_weight.saturating_add(T::WeightInfo::execute()))] pub fn execute( origin: OriginFor, - message: Box::RuntimeCall>>, + message: Box::RuntimeCall>, MaxXcmEncodedSizeUsize>>, max_weight: Weight, ) -> DispatchResultWithPostInfo { let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; - let weight_used = Self::execute_base(origin_location, message, max_weight)?; + let weight_used = Self::execute_base(origin_location, Box::new(message.value()), max_weight)?; Ok(Some(weight_used.saturating_add(T::WeightInfo::execute())).into()) } diff --git a/polkadot/xcm/xcm-builder/src/controller.rs b/polkadot/xcm/xcm-builder/src/controller.rs index 6bdde2a967de..939fbd232c17 100644 --- a/polkadot/xcm/xcm-builder/src/controller.rs +++ b/polkadot/xcm/xcm-builder/src/controller.rs @@ -48,6 +48,7 @@ pub trait ExecuteControllerWeightInfo { parameter_types! { pub const MaxXcmEncodedSize: u32 = xcm::MAX_XCM_ENCODED_SIZE; + pub const MaxXcmEncodedSizeUsize: usize = xcm::MAX_XCM_ENCODED_SIZE as usize; } /// Execute an XCM locally, for a given origin. diff --git a/polkadot/xcm/xcm-builder/src/lib.rs b/polkadot/xcm/xcm-builder/src/lib.rs index bd4a4c941c91..2ff72d7a16a3 100644 --- a/polkadot/xcm/xcm-builder/src/lib.rs +++ b/polkadot/xcm/xcm-builder/src/lib.rs @@ -43,7 +43,7 @@ pub use barriers::{ mod controller; pub use controller::{ - Controller, ExecuteController, ExecuteControllerWeightInfo, MaxXcmEncodedSize, QueryController, + Controller, ExecuteController, ExecuteControllerWeightInfo, MaxXcmEncodedSize, MaxXcmEncodedSizeUsize, QueryController, QueryControllerWeightInfo, QueryHandler, SendController, SendControllerWeightInfo, }; diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 984a7f7537fe..5ff8bbe798a9 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -76,6 +76,7 @@ pub mod storage; mod tests; pub mod traits; pub mod weights; +pub mod utils; #[doc(hidden)] pub mod unsigned { #[doc(hidden)] @@ -103,6 +104,7 @@ pub use self::{ IterableStorageDoubleMap, IterableStorageMap, IterableStorageNMap, StorageDoubleMap, StorageMap, StorageNMap, StoragePrefixedMap, StorageValue, }, + utils::WithMaxSize, }; pub use sp_runtime::{ self, print, traits::Printable, ConsensusEngineId, MAX_MODULE_ERROR_ENCODED_SIZE, diff --git a/substrate/frame/support/src/utils.rs b/substrate/frame/support/src/utils.rs new file mode 100644 index 000000000000..65733a70a68c --- /dev/null +++ b/substrate/frame/support/src/utils.rs @@ -0,0 +1,91 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use codec::{Encode, Decode, Input, MaxEncodedLen}; +use frame_support_procedural::{EqNoBound, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound}; +use scale_info::TypeInfo; +use sp_core::Get; + +use crate::Parameter; + +/// TODO: docs +pub struct InputWithMaxLength<'a, I: Input, S: Get> { + input: &'a mut I, + len: usize, + _phantom: core::marker::PhantomData, +} + +impl<'a, I: Input, S: Get> InputWithMaxLength<'a, I, S> { + pub fn new(input: &'a mut I) -> Self { + Self { input, len: S::get(), _phantom: Default::default() } + } +} + +impl<'a, I: Input, S: Get> Input for InputWithMaxLength<'a, I, S> { + fn remaining_len(&mut self) -> Result, codec::Error> { + let len = self.input.remaining_len()?; + Ok(len.map(|l| l.min(self.len))) + } + + fn read(&mut self, into: &mut [u8]) -> Result<(), codec::Error> { + let max_len = self.len.min(into.len()); + self.len -= max_len; + self.input.read(&mut into[..max_len])?; + Ok(()) + } +} + +/// TODO: docs +#[derive(Encode, EqNoBound, PartialEqNoBound, CloneNoBound, TypeInfo, RuntimeDebugNoBound)] +#[scale_info(skip_type_params(S))] +pub struct WithMaxSize> { + value: T, + _phantom: core::marker::PhantomData, +} + +impl> WithMaxSize { + /// TODO: docs + pub fn unchecked_new(value: T) -> Self { + Self { value, _phantom: Default::default() } + } + + /// TODO: docs + pub fn new(value: T) -> Result { + if value.encoded_size() <= S::get() { + Ok(Self { value, _phantom: Default::default() }) + } else { + Err(()) + } + } + + pub fn value(self) -> T { + self.value + } +} + +impl> MaxEncodedLen for WithMaxSize { + fn max_encoded_len() -> usize { + S::get() + } +} + +impl> Decode for WithMaxSize { + fn decode(input: &mut I) -> Result { + let mut input = InputWithMaxLength::::new(input); + Ok(Self::unchecked_new(T::decode(&mut input)?)) + } +} From 85522f3595b6e67beb6608d129b8a1f9dc0ddb6f Mon Sep 17 00:00:00 2001 From: Bryan Chen Date: Fri, 19 Apr 2024 14:27:33 +1200 Subject: [PATCH 2/5] improvement --- substrate/frame/support/src/utils.rs | 46 ++++++++++++++++------------ 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/substrate/frame/support/src/utils.rs b/substrate/frame/support/src/utils.rs index 65733a70a68c..276edc4669a9 100644 --- a/substrate/frame/support/src/utils.rs +++ b/substrate/frame/support/src/utils.rs @@ -15,49 +15,46 @@ // See the License for the specific language governing permissions and // limitations under the License. -use codec::{Encode, Decode, Input, MaxEncodedLen}; -use frame_support_procedural::{EqNoBound, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound}; +use crate::Parameter; +use codec::{Decode, Encode, Input, MaxEncodedLen}; +use frame_support_procedural::{CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound}; use scale_info::TypeInfo; use sp_core::Get; -use crate::Parameter; - /// TODO: docs pub struct InputWithMaxLength<'a, I: Input, S: Get> { input: &'a mut I, - len: usize, + remaining_len: usize, _phantom: core::marker::PhantomData, } impl<'a, I: Input, S: Get> InputWithMaxLength<'a, I, S> { pub fn new(input: &'a mut I) -> Self { - Self { input, len: S::get(), _phantom: Default::default() } + Self { input, remaining_len: S::get(), _phantom: Default::default() } } } impl<'a, I: Input, S: Get> Input for InputWithMaxLength<'a, I, S> { fn remaining_len(&mut self) -> Result, codec::Error> { - let len = self.input.remaining_len()?; - Ok(len.map(|l| l.min(self.len))) + self.input.remaining_len().map(|l| l.map(|l| l.min(self.remaining_len))) } fn read(&mut self, into: &mut [u8]) -> Result<(), codec::Error> { - let max_len = self.len.min(into.len()); - self.len -= max_len; - self.input.read(&mut into[..max_len])?; - Ok(()) + if into.len() > self.remaining_len { + return Err("Not enough data to fill buffer".into()); + } + self.input.read(into) } } /// TODO: docs -#[derive(Encode, EqNoBound, PartialEqNoBound, CloneNoBound, TypeInfo, RuntimeDebugNoBound)] -#[scale_info(skip_type_params(S))] -pub struct WithMaxSize> { +#[derive(Encode, EqNoBound, PartialEqNoBound, CloneNoBound, RuntimeDebugNoBound)] +pub struct WithMaxSize> { value: T, _phantom: core::marker::PhantomData, } -impl> WithMaxSize { +impl> WithMaxSize { /// TODO: docs pub fn unchecked_new(value: T) -> Self { Self { value, _phantom: Default::default() } @@ -77,15 +74,26 @@ impl> WithMaxSize { } } -impl> MaxEncodedLen for WithMaxSize { +impl> MaxEncodedLen for WithMaxSize { fn max_encoded_len() -> usize { + // not using T::max_encoded_len().min(S::get()) because while it is possible + // that T::max_encoded_len() is smaller, but in that case there will be no reason + // to use WithMaxSize S::get() } } -impl> Decode for WithMaxSize { +impl> Decode for WithMaxSize { fn decode(input: &mut I) -> Result { let mut input = InputWithMaxLength::::new(input); - Ok(Self::unchecked_new(T::decode(&mut input)?)) + Ok(Self::unchecked_new(T::decode(&mut input)?)) + } +} + +impl> TypeInfo for WithMaxSize { + type Identity = T; + + fn type_info() -> scale_info::Type { + T::type_info() } } From daf0966bc508a9fb2281959db2aedcafa10cd829 Mon Sep 17 00:00:00 2001 From: Bryan Chen Date: Fri, 19 Apr 2024 14:33:42 +1200 Subject: [PATCH 3/5] fmt --- polkadot/xcm/pallet-xcm/src/lib.rs | 11 +++++++---- polkadot/xcm/xcm-builder/src/lib.rs | 5 +++-- substrate/frame/support/src/lib.rs | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 8f1a3c5b5966..bdb6ca55a241 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -50,8 +50,8 @@ use sp_runtime::{ use sp_std::{boxed::Box, marker::PhantomData, prelude::*, result::Result, vec}; use xcm::{latest::QueryResponseInfo, prelude::*}; use xcm_builder::{ - ExecuteController, ExecuteControllerWeightInfo, MaxXcmEncodedSize, MaxXcmEncodedSizeUsize, QueryController, - QueryControllerWeightInfo, SendController, SendControllerWeightInfo, + ExecuteController, ExecuteControllerWeightInfo, MaxXcmEncodedSize, MaxXcmEncodedSizeUsize, + QueryController, QueryControllerWeightInfo, SendController, SendControllerWeightInfo, }; use xcm_executor::{ traits::{ @@ -1057,11 +1057,14 @@ pub mod pallet { #[pallet::weight(max_weight.saturating_add(T::WeightInfo::execute()))] pub fn execute( origin: OriginFor, - message: Box::RuntimeCall>, MaxXcmEncodedSizeUsize>>, + message: Box< + WithMaxSize::RuntimeCall>, MaxXcmEncodedSizeUsize>, + >, max_weight: Weight, ) -> DispatchResultWithPostInfo { let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; - let weight_used = Self::execute_base(origin_location, Box::new(message.value()), max_weight)?; + let weight_used = + Self::execute_base(origin_location, Box::new(message.value()), max_weight)?; Ok(Some(weight_used.saturating_add(T::WeightInfo::execute())).into()) } diff --git a/polkadot/xcm/xcm-builder/src/lib.rs b/polkadot/xcm/xcm-builder/src/lib.rs index 2ff72d7a16a3..d52b4fce2bf9 100644 --- a/polkadot/xcm/xcm-builder/src/lib.rs +++ b/polkadot/xcm/xcm-builder/src/lib.rs @@ -43,8 +43,9 @@ pub use barriers::{ mod controller; pub use controller::{ - Controller, ExecuteController, ExecuteControllerWeightInfo, MaxXcmEncodedSize, MaxXcmEncodedSizeUsize, QueryController, - QueryControllerWeightInfo, QueryHandler, SendController, SendControllerWeightInfo, + Controller, ExecuteController, ExecuteControllerWeightInfo, MaxXcmEncodedSize, + MaxXcmEncodedSizeUsize, QueryController, QueryControllerWeightInfo, QueryHandler, + SendController, SendControllerWeightInfo, }; mod currency_adapter; diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 5ff8bbe798a9..d4605f964077 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -75,8 +75,8 @@ pub mod storage; #[cfg(test)] mod tests; pub mod traits; -pub mod weights; pub mod utils; +pub mod weights; #[doc(hidden)] pub mod unsigned { #[doc(hidden)] From 2f6db4dfe0cbc30ef59ab822801994d6ada5b19c Mon Sep 17 00:00:00 2001 From: Bryan Chen Date: Fri, 19 Apr 2024 21:34:14 +1200 Subject: [PATCH 4/5] fix test --- .../xcm/xcm-executor/integration-tests/src/lib.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs b/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs index 279d7118f8cf..94a51270db96 100644 --- a/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs +++ b/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs @@ -17,7 +17,7 @@ #![cfg(test)] use codec::Encode; -use frame_support::{dispatch::GetDispatchInfo, weights::Weight}; +use frame_support::{dispatch::GetDispatchInfo, weights::Weight, WithMaxSize}; use polkadot_service::chain_spec::get_account_id_from_seed; use polkadot_test_client::{ BlockBuilderExt, ClientBlockImportExt, DefaultTestClientBuilderExt, InitPolkadotBlockBuilder, @@ -47,7 +47,7 @@ fn basic_buy_fees_message_executes() { let execute = construct_extrinsic( &client, polkadot_test_runtime::RuntimeCall::Xcm(pallet_xcm::Call::execute { - message: Box::new(VersionedXcm::from(msg)), + message: Box::new(WithMaxSize::new(VersionedXcm::from(msg)).expect("XCM is valid")), max_weight: Weight::from_parts(1_000_000_000, 1024 * 1024), }), sp_keyring::Sr25519Keyring::Alice, @@ -122,7 +122,7 @@ fn transact_recursion_limit_works() { } let max_weight = ::Weigher::weight(&mut msg).unwrap(); call = Some(polkadot_test_runtime::RuntimeCall::Xcm(pallet_xcm::Call::execute { - message: Box::new(VersionedXcm::from(msg.clone())), + message: Box::new(WithMaxSize::new(VersionedXcm::from(msg.clone())).expect("XCM is valid")), max_weight, })); } @@ -212,12 +212,11 @@ fn query_response_fires() { let max_weight = Weight::from_parts(1_000_000, 1024 * 1024); let querier = Some(Here.into()); let msg = Xcm(vec![QueryResponse { query_id, response, max_weight, querier }]); - let msg = Box::new(VersionedXcm::from(msg)); let execute = construct_extrinsic( &client, polkadot_test_runtime::RuntimeCall::Xcm(pallet_xcm::Call::execute { - message: msg, + message: Box::new(WithMaxSize::new(VersionedXcm::from(msg)).expect("XCM is valid")), max_weight: Weight::from_parts(1_000_000_000, 1024 * 1024), }), sp_keyring::Sr25519Keyring::Alice, @@ -298,7 +297,7 @@ fn query_response_elicits_handler() { let execute = construct_extrinsic( &client, polkadot_test_runtime::RuntimeCall::Xcm(pallet_xcm::Call::execute { - message: Box::new(VersionedXcm::from(msg)), + message: Box::new(WithMaxSize::new(VersionedXcm::from(msg)).expect("XCM is valid")), max_weight: Weight::from_parts(1_000_000_000, 1024 * 1024), }), sp_keyring::Sr25519Keyring::Alice, @@ -381,7 +380,7 @@ fn deposit_reserve_asset_works_for_any_xcm_sender() { let execute = construct_extrinsic( &client, polkadot_test_runtime::RuntimeCall::Xcm(pallet_xcm::Call::execute { - message: Box::new(VersionedXcm::from(msg)), + message: Box::new(WithMaxSize::new(VersionedXcm::from(msg)).expect("XCM is valid")), max_weight: Weight::from_parts(1_000_000_000, 1024 * 1024), }), sp_keyring::Sr25519Keyring::Alice, From 14731d3ff154c9be3ea35c77d58be5c12421fdcb Mon Sep 17 00:00:00 2001 From: Bryan Chen Date: Fri, 19 Apr 2024 21:41:57 +1200 Subject: [PATCH 5/5] fmt --- polkadot/xcm/xcm-executor/integration-tests/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs b/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs index 94a51270db96..3e2661d40213 100644 --- a/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs +++ b/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs @@ -122,7 +122,9 @@ fn transact_recursion_limit_works() { } let max_weight = ::Weigher::weight(&mut msg).unwrap(); call = Some(polkadot_test_runtime::RuntimeCall::Xcm(pallet_xcm::Call::execute { - message: Box::new(WithMaxSize::new(VersionedXcm::from(msg.clone())).expect("XCM is valid")), + message: Box::new( + WithMaxSize::new(VersionedXcm::from(msg.clone())).expect("XCM is valid"), + ), max_weight, })); }