7

When building my pallet, I run into the error:

error[E0277]: the trait bound `T: parity_scale_codec::MaxEncodedLen` is not satisfied
  --> pallets/template/src/lib.rs:42:15
   |
42 |     #[pallet::pallet]
   |               ^^^^^^ the trait `parity_scale_codec::MaxEncodedLen` is not implemented for `T`
   |
note: required because of the requirements on the impl of `parity_scale_codec::MaxEncodedLen` for `Kitty<T>`
  --> pallets/template/src/lib.rs:25:69
   |
25 |     #[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
   |                                                                        ^^^^^^^^^^^^^
26 |     #[scale_info(skip_type_params(T))]
27 |     pub struct Kitty<T: Config> {
   |                ^^^^^^^^^^^^^^^^
   = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageMap<_GeneratedPrefixForStorageKitties<T>, frame_support::Twox64Concat, <T as frame_system::Config>::Hash, Kitty<T>>`
   = note: this error originates in the derive macro `MaxEncodedLen` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider further restricting this bound
   |
42 |     #[pallet::pallet + parity_scale_codec::MaxEncodedLen]
   |                      +++++++++++++++++++++++++++++++++++

For more information about this error, try `rustc --explain E0277`.
error: could not compile `pallet-template` due to previous error
warning: build failed, waiting for other jobs to finish...
error: build failed

The custom type definitions are:

// Struct for holding Kitty information.
#[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
#[scale_info(skip_type_params(T))]
pub struct Kitty<T: Config> {
    pub dna: [u8; 16],   // Using 16 bytes to represent a kitty DNA
    pub price: Option<BalanceOf<T>>,
    pub gender: Gender,
    pub owner: AccountOf<T>,
}

// Enum declaration for Gender.
#[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum Gender {
    Male,
    Female,
}

As far as I know, MaxEncodedLen should work for Kitty since all of its fields are also bounded in length.

How do I resolve this issue?

1 Answer 1

6

The underlying issue here is that Rust macros are not super intelligent.

While you are correct that all the interior fields of Kitty is bounded in length, you are also using the generic type T: Config to help access some of those types.

The Rust macros for automatically deriving MaxEncodedLen naively thinks that T must also be bounded by MaxEncodedLen, even though T itself is not being used in the actual types.

We can fix this in one of two ways:

  1. Add a simple "hint" to the compiler in the form of #[codec(mel_bound())].

    // Struct for holding Kitty information.
    #[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
    #[scale_info(skip_type_params(T))]
    #[codec(mel_bound())] // <---------------- Here
    pub struct Kitty<T: Config> {
        pub dna: [u8; 16],   // Using 16 bytes to represent a kitty DNA
        pub price: Option<BalanceOf<T>>,
        pub gender: Gender,
        pub owner: AccountOf<T>,
    }
    

    Oversimplifying, this will allow the compiler to skip trying to derive MaxEncodedLen for T, and just check the underlying types themselves all have MaxEncodedLen.

  2. Do not use <T: Config> when defining Kitties.

    Instead, make generic only the types you need:

    // Struct for holding Kitty information.
    #[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
    pub struct Kitty<Account, Balance> {
        pub dna: [u8; 16],   // Using 16 bytes to represent a kitty DNA
        pub price: Option<Balance>,
        pub gender: Gender,
        pub owner: Account,
    }
    

    In this case, we have been able to remove T completely from the struct definition, and thus will have no complaints from the derive macro about trying to implement MaxEncodedLen for it. Note that we were also able to get rid of #[scale_info(skip_type_params(T))] from the definition aswell, since this basically doing the same thing as #[codec(mel_bound())] above.

2
  • 1
    That's a great explanation. I guess this must be in the tutorial as well. Mar 25 at 7:34
  • I was searching substrate crates to get more information around mel_bound(). Can you throw some document pointers to #[codec(mel_bound())]? Mar 25 at 22:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.