3

Can you tell me how to mock a trait in benchmarking?

We have a pallet which takes NFTTrait as one of the configs. See below.

    #[pallet::config]
    pub trait Config: frame_system::Config {
        type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
        /// NFT Handler
        type NFTHandler: NFTTrait<Self::AccountId, ClassId = ClassId, TokenId = TokenId>;
    }

In the mock, we have created a struct to mock NFTTrait and pass it to the config.

pub struct NFTHandler;

impl NFTTrait<u128> for NFTHandler {
   fn check_ownership(who: &AccountId, asset_id: &Self::AssetId) -> Result<bool>;
}

impl Config for Runtime {
    type Event = Event;
    type NFTHandler = NFTHandler;
}

So how do I achieve the same thing in benchmarking? I tried to add use crate::mock::NFTHandler; on top of benchmarking class. Although IDE can find the correct reference, it did give me an error when I built it.

error[E0432]: unresolved import `crate::mock`
  --> pallets/marketplace/src/benchmarking.rs:34:12
   |
34 | use crate::mock::NFTHandler;
   |            ^^^^ could not find `mock` in the crate root

Below is a snippet from benchmarking file

#![cfg(feature = "runtime-benchmarks")]

use super::*;
use sp_std::prelude::*;
use sp_std::vec;

#[allow(unused)]
use crate::*;
use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller};
use frame_support::traits::{Currency, Get};
use frame_system::RawOrigin;
use pallet_nft::{Attributes, CollectionType, TokenType};
use sp_runtime::traits::{AccountIdConversion, StaticLookup, UniqueSaturatedInto};
use crate::{Call, Config};
use crate::mock::NFTHandler;


const SEED: u32 = 0;
pub type AccountId = u128;
pub type AssetId = u128;

const ALICE: AccountId = 1;
const NFT_ID: AssetId = 99;

fn mint_NFT<T: Config>(caller: T::AccountId) {
    NFTModule::<T>::mint(
        RawOrigin::Signed(caller.clone()).into(),
        ALICE,
        test_attributes(1)      
    );
}

benchmarks! {   
    list_item{
        let caller: T::AccountId = account('caller', 0, SEED);

        mint_NFT::<T>(caller.clone());
    }: _(RawOrigin::Signed(caller.clone()), NFT_ID)
    verify {
        let listing_id = crate::Pallet::<T>::get_listing_item(NFT_ID);
        assert_eq!(listing_id, 0);
    }
}

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

Any suggestions are welcome, thanks

5
  • You are going to need to share the code in your benchmarking file.
    – Shawn Tabrizi
    Mar 23, 2022 at 21:44
  • Thanks @ShawnTabrizi, could you provide an example or code snippet?
    – Jerry Ren
    Mar 23, 2022 at 22:02
  • Why are you asking me to share code? You are showing an error, but not showing the code which got you to this error. You need to provide a Minimum, Reproducible Example.
    – Shawn Tabrizi
    Mar 23, 2022 at 22:09
  • Sorry @ShawnTabrizi, my bad, wasn't thinking. I thought you were suggesting code sharing between mock and benchmarking file. Anyway, I have add a code snippet of our benchmarking file. Thanks
    – Jerry Ren
    Mar 23, 2022 at 22:36
  • 1
    Sorry for making this an answer; it won't let me comment without 50 rep first :/ We're trying to do the exact thing above, however, the benchmarks are calling the runtime config version and not the mock config version of the trait implementation, and I can't figure out why. The mock pallet config is set to use T::AccountHandler, defined inside mock.rs, for a defined AccountProvider trait. mock.rs: ``` pub struct AccountHandler; impl AccountProvider<AccountId, BlockNumber> for AccountHandler { fn get_msa_id(key: &AccountId) -> Option<MessageSenderId> { // etc. } } impl pallet_messages::Conf Jun 4, 2022 at 0:32

1 Answer 1

4

My guess is that your mock is only accessible when compiling with the test flag, like so:

#[cfg(test)]
mod mock;

So if you want to use this dependency, you must do so with this feature gate:

#[cfg(test)]
use crate::mock::NFTHandler;

And note that you cannot really write any non-test code which uses this dependency since it wont compile when you actually want to run benchmarks.

Instead, you probably DON'T want to import struct NFTHandler, but instead use your trait:

T::NFTHandler::check_ownership(...)

Which should require no imports from mock.

4
  • Thanks Shawn. I suppose T::NFTHandler::check_ownership(...) will be calling the things I put inside mock file. Is that correct?
    – Jerry Ren
    Mar 24, 2022 at 3:28
  • Yes, it will call however you implement your runtime. So for tests, it will call the mock, but then when doing REAL benchmarks, it will call the real implementation. That is the flexibility of Rust and Substrate.
    – Shawn Tabrizi
    Mar 24, 2022 at 3:41
  • Thank you @shawn-tabrizi
    – Jerry Ren
    Mar 24, 2022 at 5:12
  • Hi Shawn, in the benchmarking file, how did you reference another pallet that defined in the runtime?
    – Jerry Ren
    Mar 24, 2022 at 23:48

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.