3

One of benchmarked extrinsic of custom pallet requires Root sender (or Sudo), uses pallet_assets from runtime trait implementation (no coupling here). To verify I'm using balance() method to confirm asset is present. One of inputs for that is AccountId, so I need to convert RawOrigin::Root to AccountId somehow. Thanks.

Pallet

//--- snip ---
#[frame_support::pallet]
pub mod pallet {
    #[pallet::config]
    pub trait Config: frame_system::Config {
//--- snip ---
        type AssertCreateUpdateOrigin: EnsureOrigin<<Self as frame_system::Config>::Origin>;
//--- snip ---
    }
//--- snip ---
    #[pallet::call]
    impl<T: Config> Pallet<T> {
        #[pallet::weight(100_000)]
        pub fn extrinsic_call(origin: OriginFor<T>) -> DispatchResult 
        {
            T::AssetCreateUpdateOrigin::ensure_origin(origin)?;
        //--- snip ---
        }
//--- snip ---
    }
}

Benchmark

benchmarks! {
    extrinsic_call {
        let b in 0 .. u8::MAX;
        let account: T::AccountId = RawOrigin::Root.into(); // <<<--- THIS NEEDS TO WORK SOMEHOW 
        let id = H160::from_slice(&[bu8; 20]);
    }: _(RawOrigin::Root, id)
    verify {
        assert_eq!(0, T::AssetManager::balance(u128::from_be_bytes([bu8; 16]), &account));
    }
}
2
  • 1
    Could you maybe post the code of your extrinsic and the benchmark or test that you try to write? Mar 11, 2022 at 12:38
  • created minimal example Mar 11, 2022 at 14:37

2 Answers 2

2

When writing benchmarks which use EnsureOrigin, you should be using the specific helper function successful_origin which is meant for exactly this scenario:

/// Some sort of check on the origin is performed by this object.
pub trait EnsureOrigin<OuterOrigin> {
    /// A return type.
    type Success;

    /// Perform the origin check.
    fn ensure_origin(o: OuterOrigin) -> Result<Self::Success, BadOrigin> {
        Self::try_origin(o).map_err(|_| BadOrigin)
    }

    /// Perform the origin check.
    fn try_origin(o: OuterOrigin) -> Result<Self::Success, OuterOrigin>;

    /// Returns an outer origin capable of passing `try_origin` check.
    ///
    /// ** Should be used for benchmarking only!!! **
    #[cfg(feature = "runtime-benchmarks")]
    fn successful_origin() -> OuterOrigin;
}

In this case, you do not need to assume how a user has implemented the EnsureOrigin trait, since they will be required to provide an answer to how to pass this check.

Now, one implementation of this COULD be RawOrigin::Root, but then you DEFINITELY cannot assume that you can create an AccountId from this.

It says to me your logic is fundamentally flawed, since an Origin != Account. Only one of the possible origins, specifically Origin::Signed can be resolved into an AccountId.

1

If you need to ensure that AssertCreateUpdateOrigin resolves into an AccountId, consider placing a bound on the Success type:

type AssertCreateUpdateOrigin: EnsureOrigin<<Self as frame_system::Config>::Origin, Success=Self::AccountId>;

You can then use:

let account = AssertCreateUpdateOrigin::ensure_origin(origin)?;

This will either bail with an error or properly populate account with an value determined by the origin. As @shawn says, it is up to the implementer of AssertCreateUpdateOrigin to ensure that a successful origin actually exists for the purpose of benchmarking and you can get access to such an origin by using AssetCreateUpdateOrigin::successful_origin().

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.