0

I am unable to get benchmarks to work after changing an extrinsic argument from Vec<u8> to a custom type which is a BoundedVec defined in the pallet pallets config.

  1. Can someone provide me with more insights into why the BoundedVec is acting differently in the benchmark-runtime.

  2. As well as an implementation that converts a string into a valid BoundedVec type, I don't really want to define my extrinsic argument to be Vec, then convert them in the runtime just to satisfy the benchmarks.

Example:

#[pallet::config]
pub trait Config: frame_system::Config {
#...

type Bytes: Parameter
 + Member
 + MaybeSerializeDeserialize
 + MaxEncodedLen
 + Into<Vec<u8>>;

# ...
}

# ...
#[pallet::call]
impl<T: Config<I>, I: 'static> Pallet<T, I> {

  #[pallet::call_index(0)]
  #[pallet::weight(0)]
  fn do_something(origin: OriginFor<T>, bytes: T::Bytes) {
    # Note: T::Bytes used to be bytes: Vec<u8>
    # ...
  }
}

The runtime and tests are working correctly, however, when it comes to creating a BoundedVec in the runtime-benchmarks I'm struggling to construct the type required for calling the extrinsic in the benchmarks.

Example of how I am successfully calling the extrinsic from the tests using this conversion from string to the custom BoundedVec type.


# mock.rs
parameter_types! {
    pub const MaxSize: u32 = 128;
}

pub type Bytes = BoundedVec<u8, MaxSize>;

impl pallet::Config for Test {
  # ...
  type Bytes = Bytes;
}
# test.rs
#[test]
fn it_does_something() {
new_test_ext().execute_with(|| {
  let bytes: Bytes = "hello world!"
    .as_bytes()
    .to_vec()
    .try_into()
    .unwrap()
  
  assert_ok!(Pallet::do_something(RuntimeOrigin::signed(1), bytes);
  }
}

I cannot follow the same approach to creating my BoundedVec as I do in the tests/mock files as I get the following error. the trait From<frame_benchmarking::Vec<u8>> is not implemented for <T as pallet::Config>::Bytes

Adding additional traits to the Bytes type + TryFrom<Vec<u8>> results in other additional errors.

"hello world!".as_bytes().to_vec().try_into().unwrap()
                                              ^^^^^^ `<<T as pallet::Config>::Bytes as TryFrom<frame_benchmarking::Vec<u8>>>::Error` cannot be formatted using `{:?}` because it doesn't implement `core::fmt::Debug`

adding the suggested where just unravels additional errors so it doesn't seem like the correct approach.
#![cfg(feature = "runtime-benchmarks")]

use super::*;

use crate::Pallet;
use frame_benchmarking::{benchmarks, whitelisted_caller};
use frame_system::RawOrigin;


# The function I would like to work. previously It was just returning a Vec<u8>.
fn bytes<T: Config>() -> T::Bytes {
    "hello world!".as_bytes().to_vec().try_into().unwrap()
}

benchmarks! {
    do_something_benchmark {
        let caller: T::AccountId = whitelisted_caller();
    }: do_something(RawOrigin::Signed(caller.clone()), bytes::<T>())
     verify {
        assert_eq!(Pallet::<T>::storage().unwrap().len(), 1);
    }

    impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test);
}

1 Answer 1

1

Okay after all of that, I managed to figure it out...

Since frame_benchmarking::Vec<u8> wasn't working I decided to focus on converting a BoundedVec to the custom type.

  1. Firstly I needed to add the Bytes MaxSize into the config so I can refer to it in the From trait.
#[pallet::config]
pub trait Config: frame_system::Config {
#...
type MaxSize: Get<u32>;

type Bytes: Parameter
 + Member
 + MaybeSerializeDeserialize
 + MaxEncodedLen
 + Into<Vec<u8>>
 + From<BoundedVec<u8, Self::MaxSize>>; 
# ...
}
  1. Update the runtimes to pass in the additonal type.
impl pallet::Config for Test {
  # ...
  type MaxSize = MaxSize;
  type Bytes = Bytes;
}
  1. update the benchmark code
#![cfg(feature = "runtime-benchmarks")]

use super::*;

use crate::Pallet;
use frame_benchmarking::{benchmarks, whitelisted_caller};
use frame_system::RawOrigin;


benchmarks! {
    do_something_benchmark {
        let caller: T::AccountId = whitelisted_caller();

        // Use the BoundedVec TryFrom<Vec> trait
        let bv_bytes: BoundedVec::<u8, T::MaxSize> = "hello world!".as_bytes().to_vec().try_into().unwrap(); 

        // Use the newly defined From<BoundedVec<u8, Self::MaxSize>> trait
        let bytes = T::Bytes::from(bv_bytes);
    }: do_something(RawOrigin::Signed(caller.clone()), bytes)
     verify {
        assert_eq!(Pallet::<T>::storage().unwrap().len(), 1);
    }

    impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test);
}

I hope this helps someone else who runs into a similar issue in the future!

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.