Skip to content

Commit

Permalink
Fix WrapperOpaque max encded len and type info (paritytech#9881)
Browse files Browse the repository at this point in the history
* fix wrapper opaque

* fix compilation

* improve more precise implementation

* spacing

* fmt
  • Loading branch information
gui1117 authored Sep 29, 2021
1 parent 7cf99b1 commit 95c81d2
Showing 1 changed file with 54 additions and 5 deletions.
59 changes: 54 additions & 5 deletions frame/support/src/traits/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -384,16 +385,15 @@ impl<Call, Balance: From<u32>, const T: u32> EstimateCallFee<Call, Balance> 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<u8>`.
#[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<T>(pub T);

impl<T: Encode> EncodeLike for WrapperOpaque<T> {}

impl<T: Encode> Encode for WrapperOpaque<T> {
fn size_hint(&self) -> usize {
// Compact<u32> usually takes at most 4 bytes
self.0.size_hint().saturating_add(4)
self.0.size_hint().saturating_add(<codec::Compact<u32>>::max_encoded_len())
}

fn encode_to<O: codec::Output + ?Sized>(&self, dest: &mut O) {
Expand Down Expand Up @@ -425,6 +425,37 @@ impl<T> From<T> for WrapperOpaque<T> {
}
}

impl<T: MaxEncodedLen> MaxEncodedLen for WrapperOpaque<T> {
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 {
<codec::Compact<u32>>::max_encoded_len().saturating_add(T::max_encoded_len())
}
}
}

impl<T: TypeInfo + 'static> TypeInfo for WrapperOpaque<T> {
type Identity = Self;
fn type_info() -> Type {
Type::builder()
.path(Path::new("WrapperOpaque", module_path!()))
.type_params(vec![TypeParameter::new("T", Some(meta_type::<T>()))])
.composite(
Fields::unnamed()
.field(|f| f.compact::<u32>().type_name("EncodedLengthOfT"))
.field(|f| f.ty::<T>().type_name("T")),
)
}
}

#[cfg(test)]
mod test {
use super::*;
Expand All @@ -438,5 +469,23 @@ mod test {
assert_eq!(decoded_from_vec_u8, 3u32);
let decoded = <WrapperOpaque<u32>>::decode(&mut &encoded[..]).unwrap();
assert_eq!(decoded.0, 3u32);

assert_eq!(<WrapperOpaque<[u8; 63]>>::max_encoded_len(), 63 + 1);
assert_eq!(
<WrapperOpaque<[u8; 63]>>::max_encoded_len(),
WrapperOpaque([0u8; 63]).encode().len()
);

assert_eq!(<WrapperOpaque<[u8; 64]>>::max_encoded_len(), 64 + 2);
assert_eq!(
<WrapperOpaque<[u8; 64]>>::max_encoded_len(),
WrapperOpaque([0u8; 64]).encode().len()
);

assert_eq!(
<WrapperOpaque<[u8; 2usize.pow(14) - 1]>>::max_encoded_len(),
2usize.pow(14) - 1 + 2
);
assert_eq!(<WrapperOpaque<[u8; 2usize.pow(14)]>>::max_encoded_len(), 2usize.pow(14) + 4);
}
}

0 comments on commit 95c81d2

Please sign in to comment.