on_initialize
has the advantage of being in the Mandatory
dispatch class.
It can consume an unlimited amount of weight; even stall the chain if necessary.
This is what often happens for large runtime migrations that do not fit in one block.
In your case you want to stay within max_block
as not to stall the chain.
Good examples for this are the scheduler and state-trie-migration pallets.
The scheduler has a pallet constant to configure a limit. Currently set to 80% of max_block
:
pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) *
BlockWeights::get().max_block;
To analyze what is a good value here, you can directly look at the BlockWeights of your runtime. Just print it in a test. For Polkadot this print:
base_block: 53_99_176_000
max_block: 2_000_000_000_000
per_class:
normal:
base_extrinsic: 85_212_000
max_extrinsic: Some(1_479_914_788_000)
max_total: Some(1_500_000_000_000)
reserved: Some(0)
operational:
base_extrinsic: 85_212_000
max_extrinsic: Some(1_979_914_788_000)
max_total: Some(2_000_000_000_000)
reserved: Some(500_000_000_000)
mandatory:
base_extrinsic: 85_212_000
max_extrinsic: None
max_total: None
reserved: None
Personally I am not sure if it makes sense to aim for a perfect value here, since you either:
- Want to get it done ASAP: don't track the weight and just stall the chain. This may or may not be a good idea depending on your needs.
- Have a preemptable task: Pick some limit like 80% and leave some room for other important extrinsics.
Hopefully this answers your question. For completeness I will still try to find out what the theoretical maximum value would be and update this answer.