1

There is very little information to be found on static parameter types. All I could find is a docstring that says: In testing, StaticArgument can be altered later: StaticArgument::set(8).

I need to alter a parameter in benchmarking code to be able to benchmark a specific path Pallet config:

#[pallet::config]
pub trait Config: frame_system::Config {
  type HeadersToKeep: Get<u32>;
}

In the runtime code the parameter is declared as static:

parameter_types! {
    pub static HeadersToKeepArgument: u32 = 1000;
}

Passed to the config:

impl my_pallet::Config for Runtime {
    type HeadersToKeep = HeadersToKeepArgument;
}

Now when I want to set it's value to execute a benchmark code:

benchmarks! {

  benchmark_with_pruning {

    let _ = T::HeadersToKeep::set(3);

    ...

  }: foo(RawOrigin::Signed(caller.clone()))

  verify {
   ...
  }

}
75 |         let _ = T::HeadersToKeep::set(3);
   |                                   ^^^ function or associated item cannot be called on `<T as pallet::Config>::HeadersToKeep` due to unsatisfied trait bounds
   |
   = note: the following trait bounds were not satisfied:
           `<T as pallet::Config>::HeadersToKeep: frame_support::storage::generator::StorageValue<_>`
           which is required by `<T as pallet::Config>::HeadersToKeep: frame_support::StorageValue<_>`
           `&<T as pallet::Config>::HeadersToKeep: frame_support::storage::generator::StorageValue<_>`
           which is required by `&<T as pallet::Config>::HeadersToKeep: frame_support::StorageValue<_>`
           `&mut <T as pallet::Config>::HeadersToKeep: frame_support::storage::generator::StorageValue<_>`
           which is required by `&mut <T as pallet::Config>::HeadersToKeep: frame_support::StorageValue<_>`

3
  • Can you explain why the Get implementation needs to be dynamically changed? The value should be constant when implemented in your runtime, and thus, when you run benchmarks, you will get exactly the results for the value that put. In summary, I think you might be doing something wrong here.
    – Shawn Tabrizi
    Apr 25, 2022 at 15:21
  • tl;dr it's just easier this way. I need to benchmarks two paths: happy path and other path. Other path is invoked when there is more items (in the storage) than the Get parameter (1K here). It's a convoluted setup to get it over 1k and trigger that other logic, and the number of elements won't impact the compute complexity. It does not need to be dynamically changed though, conditional compilation is also a possibility, so I might just go with that.
    – fbielejec
    Apr 25, 2022 at 19:26
  • 1
    Yeah I don't think it will be possible to do what you want here for actual benchmarks. For tests, there are some tricks, but these would fail in the real runtime environment. And for good reason. Some of why this is not possible is that we use rust and type safety to ensure that things we expect to be constant are
    – Shawn Tabrizi
    Apr 25, 2022 at 21:35

3 Answers 3

1

Other than Oliver's answer, I want to point out that you are likely having the wrong mental model here.

Your benchmarking code receives T, including T::HeadersToKeep and all the other configurations as input. Your benchmarking code must behave and tested without needing to alter these values.

For example, your mental model should be like this: You should write your benchmarking code such that if HeadersToKeep has an impact on the weight, in one runtime where it is configured to a higher value, it is captured.

Nowhere in this scenario you should need to alter HeadersToKeep within a benchmark. Again, T is the input of your benchmark, and it a way for you to know the final configuration of the runtime, not to alter it.

Lastly, as noted here, set is only available in std, meaning that while you could mis-use it in native execution of benchmarks, you cannot use it in WASM at all.

0

In your case, if you want to know how the benchmark result goes after you change the constant, you can just change that, and then benchmark this pallet.

Because when you modify the constant and deploy the new runtime code, you also need to do this benchmark again, right?

3
  • in this case not really, no - I'm conditioning the constant value on the runtime-benchmarks feature atm to run the benchmark
    – fbielejec
    Apr 26, 2022 at 10:20
  • Then how about just make it as a storage value, and change it before benchmark ? Apr 26, 2022 at 10:56
  • Invoking the whole storage machinery for one integer seems like an overkill (maybe even an anti-pattern). In any case I think I have an answer. Thank you!
    – fbielejec
    Apr 26, 2022 at 11:22
0

I don't completely understand your problem here, but you can do:

benchmark_with_pruning {
    // Components must be named with a single char. _ does not work.
    let c in 0 .. 3;
    HeadersToKeepArgument::set(c);
} …

Note that you have to define the parameter_types in the benchmarking and then use it in your mock file as super::benchmarking::HeadersToKeepArgument. The other way around does not work as the benchmarking cannot access the mock.

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.