Calculating Transaction Weights
This guide shows a basic procedure for configuring weights. There are more advanced methods that suit different use cases. For simple functions with fixed amounts of storage reads, this method works well. For other use cases, see the section on weights.
Goal
Understand how to calculate transaction weights for a basic dispatch function.
Use Cases
- Assign the correct weight before a function call to storage.
- Calculate transaction fees.
Overview
Weights are an important part of Substrate development because they provide information about the maximum cost of a function in terms of the block size it will take up. This way, the weighting system checks what the cost will be before a function is executed. As runtime engineers, we care a lot about weights. Not only do they help add security checks around the functions we create, but they also force us to think about the computational resources consumed by a transaction. From that, we can figure out what fees to charge users. This guide will cover how to calculate the maximum weight for a dispatch call; calculate the actual weight after execution; and reimburse the difference. Here's an overview of the traits we'll be implementing:
PaysFee
: to specify whether or not a dispatch pays the fee.GetDispatchInfo
: carries weight information using the#[weight]
attribute.DispatchResultWithPostInfo
: provides new weight info once the extrinsic function has been executed.
Steps
1. Import weight configuration tools
Make sure you have the right dependencies:
use frame_support::Parameter;
use frame_support::weights::{GetDispatchInfo, Pays};
use sp_runtime::traits::Dispatchable;
use frame_support::pallet_prelude::{DispatchResultWithPostInfo};
use frame_support::dispatch::DispatchResult;
2. Calculate maximum weight before a function
Using call.get_dispatch_info()
, calculate the maximum possible weight before the function is declared:
#[weight = {
let dispatch_info = call.get_dispatch_info();
(dispatch_info.weight, dispatch_info.class, Pays::Yes)
}]
// Define a function header that returns DispatchResultWithPostInfo.
fn do_three_reads(origin, call: Box<<T as Config>::Call>) -> DispatchResultWithPostInfo {
// Function logic.
}
GetDispatchInfo
provides the get_dispatch_info()
method we need to retrieve information about the function's weight.
3. Calculate the actual weight linked to function's logic
The actual weight of a function call depends on the logic of the extrinsic.
After execution, we can give back fees once the actual weight has been calculated.
Handle this using the Pays
Enum and DbWeight
.
For a function whose logic does three storage reads, calculate it using DbWeight
and return it at the end of the function:
// Function returns a calculation corresponding to 3 DB reads
let check_logic_weight = T::DbWeight::get().reads(3);
return Ok(Some(check_logic_weight).into())
//Remove fee associated to weight
Ok(Pays::Yes.into())
Examples
Related material
Docs
Rust docs
Other
- Polkadot's Transaction Fees