11

I want to store String value, some topics are using Vec, but I encounted this error: error[E0599]: no function or associated item named 'max_encoded_len' found for struct 'Vec<u8>' in the current scope

My code:

    #[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
    #[scale_info(skip_type_params(T))]
    #[codec(mel_bound())]
    pub struct BizAmount<T: Config> {
        pub amount: u32,
        pub price: Option<BalanceOf<T>>,
        pub organization: Organization,
        pub owner: AccountOf<T>,
    }

    #[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
    #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
    pub struct Organization {
        pub name: Vec<u8>,
        pub code: Vec<u8>,
    }
    #[pallet::pallet]
    #[pallet::generate_store(pub(super) trait Store)]
    pub struct Pallet<T>(_);

I searched on google and not found any stuffs. Thank for your help!

3
  • 2
    Why store a string when you can store the hash of it? This puts a known limit on the amount of storage used for the variable. What is the use case for the contract needing to know the actual value of the string?
    – forgetso
    Mar 24, 2022 at 11:45
  • @forgetso I'm new so Substrate. What types I can use? thank you! Mar 24, 2022 at 11:48
  • I've added an answer with some more information
    – forgetso
    Mar 24, 2022 at 12:47

2 Answers 2

14

You are trying to derive MaxEncodedLen for your Organization. This trait can only be implemented for types that have a maximum size defined at compile time. Vec<u8> does not have a fixed length because it can grow indefinitely at runtime.

The solution is to come up with a size limit (probably configured through your Config trait) and then use BoundedVec instead of Vec.

An example of that can be observed in the uniques pallet:

trait Config {
    type KeyLimit: Get<u32>;
}

pub fn set_attribute<T: Config>(
    key: BoundedVec<u8, T::KeyLimit>,
    value: BoundedVec<u8, T::ValueLimit>,
) -> DispatchResult {}

BoundedVec behaves like a Vec except that it takes a second type argument that defines the maximum size it can have. This argument needs to implement Get<u32>. BoundedVec will enforce this limit automatically and returns an Err when pushing new elements to it in case the limit is violated.

5
  • thank for your answer, can you show an example code or links, I tried but not work. Mar 24, 2022 at 11:05
  • 2
    Added an example. Mar 24, 2022 at 18:18
  • I encounted this error error[E0277]: the trait bound '<T as pallet::Config>::KeyLimit: Clone' is not satisfied Mar 25, 2022 at 7:32
  • Another minimal example in the docs: docs.substrate.io/tutorials/v3/proof-of-existence/…
    – Nuke
    Apr 19, 2022 at 14:17
  • BoundedVec does not work with many struct macros. Use arrays instead.
    – Russo
    Mar 3, 2023 at 19:23
4

It's generally bad practice to store a string in a smart contract

In general, you should think twice if you really need String. Smart contracts usually don't use strings; those are typically used for user interactions and should live in your UI and not on the chain.

Minimizing storage usage of your contract is a best practice and you should only persist items which you need to derive state transitions in your contract.

If you still, for some reason, need to use String, then you should use the String from the ink! prelude.

Source

It's quite unlikely that your smart contract will need to know the actual value of a string. Therefore, you can simply hash the string on the client side and then store the hash in the contract.

For example, in TypeScript before calling your contract function:

import { blake2AsU8a } from '@polkadot/util-crypto'
const theString = blake2AsU8a(argVal as unknown as string)

Then in the contract, store this value as a Hash type

the_string: Hash

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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