diff --git a/substrate/frame/support/src/traits/misc.rs b/substrate/frame/support/src/traits/misc.rs index 82c5512ac1..a040f8575a 100644 --- a/substrate/frame/support/src/traits/misc.rs +++ b/substrate/frame/support/src/traits/misc.rs @@ -17,10 +17,11 @@ //! Smaller traits used in FRAME which don't need their own file. -use crate::{dispatch::Parameter, TypeInfo}; +use crate::dispatch::Parameter; use codec::{Decode, Encode, EncodeLike, Input, MaxEncodedLen}; +use scale_info::{build::Fields, meta_type, Path, Type, TypeInfo, TypeParameter}; use sp_runtime::{traits::Block as BlockT, DispatchError}; -use sp_std::vec::Vec; +use sp_std::prelude::*; /// Anything that can have a `::len()` method. pub trait Len { @@ -384,7 +385,7 @@ impl, const T: u32> EstimateCallFee for /// /// The encoding is the encoding of `T` prepended with the compact encoding of its size in bytes. /// Thus the encoded value can be decoded as a `Vec`. -#[derive(Debug, Eq, PartialEq, Default, Clone, MaxEncodedLen, TypeInfo)] +#[derive(Debug, Eq, PartialEq, Default, Clone)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub struct WrapperOpaque(pub T); @@ -392,8 +393,7 @@ impl EncodeLike for WrapperOpaque {} impl Encode for WrapperOpaque { fn size_hint(&self) -> usize { - // Compact usually takes at most 4 bytes - self.0.size_hint().saturating_add(4) + self.0.size_hint().saturating_add(>::max_encoded_len()) } fn encode_to(&self, dest: &mut O) { @@ -425,6 +425,37 @@ impl From for WrapperOpaque { } } +impl MaxEncodedLen for WrapperOpaque { + fn max_encoded_len() -> usize { + let t_max_len = T::max_encoded_len(); + + // See scale encoding https://substrate.dev/docs/en/knowledgebase/advanced/codec + if t_max_len < 64 { + t_max_len + 1 + } else if t_max_len < 2usize.pow(14) { + t_max_len + 2 + } else if t_max_len < 2usize.pow(30) { + t_max_len + 4 + } else { + >::max_encoded_len().saturating_add(T::max_encoded_len()) + } + } +} + +impl TypeInfo for WrapperOpaque { + type Identity = Self; + fn type_info() -> Type { + Type::builder() + .path(Path::new("WrapperOpaque", module_path!())) + .type_params(vec![TypeParameter::new("T", Some(meta_type::()))]) + .composite( + Fields::unnamed() + .field(|f| f.compact::().type_name("EncodedLengthOfT")) + .field(|f| f.ty::().type_name("T")), + ) + } +} + #[cfg(test)] mod test { use super::*; @@ -438,5 +469,23 @@ mod test { assert_eq!(decoded_from_vec_u8, 3u32); let decoded = >::decode(&mut &encoded[..]).unwrap(); assert_eq!(decoded.0, 3u32); + + assert_eq!(>::max_encoded_len(), 63 + 1); + assert_eq!( + >::max_encoded_len(), + WrapperOpaque([0u8; 63]).encode().len() + ); + + assert_eq!(>::max_encoded_len(), 64 + 2); + assert_eq!( + >::max_encoded_len(), + WrapperOpaque([0u8; 64]).encode().len() + ); + + assert_eq!( + >::max_encoded_len(), + 2usize.pow(14) - 1 + 2 + ); + assert_eq!(>::max_encoded_len(), 2usize.pow(14) + 4); } }