referrerpolicy=no-referrer-when-downgrade
frame_support::pallet_macros

Attribute Macro call

Source
#[call]
Expand description

Allows a pallet to declare a set of functions as a dispatchable extrinsic.

In slightly simplified terms, this macro declares the set of “transactions” of a pallet.

The exact definition of extrinsic can be found in sp_runtime::generic::UncheckedExtrinsic.

A dispatchable is a common term in FRAME, referring to process of constructing a function, and dispatching it with the correct inputs. This is commonly used with extrinsics, for example “an extrinsic has been dispatched”. See sp_runtime::traits::Dispatchable and crate::traits::UnfilteredDispatchable.

§Call Enum

The macro is called call (rather than #[pallet::extrinsics]) because of the generation of a enum Call. This enum contains only the encoding of the function arguments of the dispatchable, alongside the information needed to route it to the correct function.

The macro also ensures that the extrinsic when invoked will be wrapped via frame_support::storage::with_storage_layer to make it transactional. Thus if the extrinsic returns with an error any state changes that had already occurred will be rolled back.

#[frame_support::pallet(dev_mode)]
pub mod custom_pallet {
    #[pallet::call]
    impl<T: Config> Pallet<T> {
        pub fn some_dispatchable(_origin: OriginFor<T>, _input: u32) -> DispatchResult {
            Ok(())
        }
        pub fn other(_origin: OriginFor<T>, _input: u64) -> DispatchResult {
            Ok(())
        }
    }

    // generates something like:
    // enum Call<T: Config> {
    //  some_dispatchable { input: u32 }
    //  other { input: u64 }
    // }
}

fn main() {
    construct_runtime! {
        pub enum Runtime {
            System: frame_system,
            Custom: custom_pallet
        }
    }

    let origin: RuntimeOrigin = frame_system::RawOrigin::Signed(10).into();
    // calling into a dispatchable from within the runtime is simply a function call.
        let _ = custom_pallet::Pallet::<Runtime>::some_dispatchable(origin.clone(), 10);

    // calling into a dispatchable from the outer world involves constructing the bytes of
    let call = custom_pallet::Call::<Runtime>::some_dispatchable { input: 10 };
    let _ = call.clone().dispatch_bypass_filter(origin);

    // the routing of a dispatchable is simply done through encoding of the `Call` enum,
    // which is the index of the variant, followed by the arguments.
    assert_eq!(call.encode(), vec![0u8, 10, 0, 0, 0]);

    // notice how in the encoding of the second function, the first byte is different and
    // referring to the second variant of `enum Call`.
    let call = custom_pallet::Call::<Runtime>::other { input: 10 };
    assert_eq!(call.encode(), vec![1u8, 10, 0, 0, 0, 0, 0, 0, 0]);
}

Further properties of dispatchable functions are as follows:

WARNING: modifying dispatchables, changing their order (i.e. using call_index), removing some, etc., must be done with care. This will change the encoding of the call, and the call can be stored on-chain (e.g. in pallet-scheduler). Thus, migration might be needed. This is why the use of call_index is mandatory by default in FRAME.

§Weight info

Each call needs to define a weight.

  • The weight can be defined explicitly using the attribute #[pallet::weight($expr)] (Note that argument of the call are available inside the expression).

  • Or it can be defined implicitly, the weight info for the calls needs to be specified in the call attribute: #[pallet::call(weight = $WeightInfo)], then each call that doesn’t have explicit weight will use $WeightInfo::$call_name as the weight.

  • Or it can be simply ignored when the pallet is in dev_mode.

#[frame_support::pallet]
mod pallet {
    use frame_support::pallet_prelude::*;
    use frame_system::pallet_prelude::*;

    #[pallet::pallet]
    pub struct Pallet<T>(_);

    #[pallet::config]
    pub trait Config: frame_system::Config {
        /// Type for specifying dispatchable weights.
        type WeightInfo: WeightInfo;
    }

    /// The `WeightInfo` trait defines weight functions for dispatchable calls.
    pub trait WeightInfo {
        fn do_something() -> Weight;
        fn do_something_else() -> Weight;
    }

    #[pallet::call(weight = <T as Config>::WeightInfo)]
    impl<T: Config> Pallet<T> {
        // Explicit weight definition using `#[pallet::weight(...)]`
        #[pallet::weight(<T as Config>::WeightInfo::do_something())]
        #[pallet::call_index(0)]
        pub fn do_something(
            origin: OriginFor<T>,
            foo: u32,
        ) -> DispatchResult {
            // Function logic here
            Ok(())
        }

        // Implicit weight definition, the macro looks up to the weight info defined in
        // `#[pallet::call(weight = $WeightInfo)]` attribute. Then use
        // `$WeightInfo::do_something_else` as the weight function.
        #[pallet::call_index(1)]
        pub fn do_something_else(
            origin: OriginFor<T>,
            bar: u64,
        ) -> DispatchResult {
            // Function logic here
            Ok(())
        }
    }
}

§Default Behavior

If no #[pallet::call] exists, then a default implementation corresponding to the following code is automatically generated:

#[frame_support::pallet(dev_mode)]
mod pallet {
	#[pallet::pallet]
	pub struct Pallet<T>(_);

	#[pallet::call] // <- automatically generated
	impl<T: Config> Pallet<T> {} // <- automatically generated

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

§Note on deprecation of Calls

  • Usage of deprecated attribute will propagate deprecation information to the pallet metadata where the item was declared.
  • For general usage examples of deprecated attribute please refer to https://doc.rust-lang.org/nightly/reference/attributes/diagnostics.html#the-deprecated-attribute
  • Usage of allow(deprecated) on the item will propagate this attribute to the generated code.
  • If the item is annotated with deprecated attribute then the generated code will be automatically annotated with allow(deprecated)

Documentation for this macro can be found at frame_support::pallet_macros::call.