#[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.
#[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:
- Unless if annotated by
dev_mode
, it must containweight
to denote the pre-dispatch weight consumed. - The dispatchable must declare its index via
call_index
, which can override the position of a function inenum Call
. - The first argument is always an
OriginFor
(orT::RuntimeOrigin
). - The return type is always
crate::dispatch::DispatchResult
(orcrate::dispatch::DispatchResultWithPostInfo
).
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
Documentation for this macro can be found at frame_support::pallet_macros::call
.