0

I want to clear a StorageMap in on_finalize() hook function. The code like this:

        //clear current epoch data for the next cycle
        let mut mrr: MultiRemovalResults = <CurrentEpochData<T>>::clear(10000, None);
        loop {
            match mrr.maybe_cursor{
                None => break,
                Some(v) => {
                    mrr = <CurrentEpochData<T>>::clear(10000, Some(&v[..]));
                }
            }
        }

The code above is written in on_finalize, and I am not sure if I can do this. I am afraid that there is some limitation with on_finalize hook, such as time limit or weight limit.

Need help!!!

1

2 Answers 2

1

on_finalize is guaranteed to run at the end of a block. A trick is to move the logic rather to on_initialize instead of on_finalize. You could potentially leave it in on_finalize, if you know exactly how much weight on_finalize takes and add that additional weight to on_initialize.


I couldn't find the method clear implemented for the StorageMap here. You should probably think about using remove_all or drain for clearing the StorageMap.

In addition to that, I would probably making absolutely sure, that you don't remove (and therefore make a storage write) too many values of the StorageMap in one block, because storage writes are expensive. This is the reason, why there is a limit specified for the usage of remove_all.


Yes, you are absolutely right, that there is a limit of maximal computation (weight) for each block.

But on_finalize can exceed the maximal block limit, because the hook is in the Mandatory dispatch class. The drawback of this is a longer block execution time than the expected target block time (like 6 seconds for Kusama). But as long as you count the weights for each action (on_initialize, on_finalize, on_runtime_upgrade and the dispatch functions) correctly, then and only then, the on_finalize leads to no overweight in the block.

You can see an example of removing items with a RemoveKeysLimit configuration constant here. The remove doesn't happen on a StorageMap, but you should use this principle with drain accordingly.

I hope this answers your question.

3
  • What do you mean in the first para when you say : " add that additional weight to on_initialize." ? Mar 16, 2023 at 10:37
  • I meant that you would need to calculate the weight of on_finalize and reserve that beforehand with on_initialize. (So that you have enough space for the execution of on_finalize)
    – Chralt
    Mar 16, 2023 at 18:57
  • 1
    Okay that makes sense. Thanks! Mar 17, 2023 at 6:46
1

There are multiple possibilities here depending on your needs.

  • Using a runtime migration when there are large one-time changes to be made.
  • Using on_idle to lazily do some cleanup. on_idle get the remaining weight as argument, so you can calculate how much operations you can do. This is easier to use than a migration IMO.

With on_initialize and on_finalize you need to be careful not to go overweight, otherwise the block could be rejected by collators if this happens on a para-chain.

EDIT: To actually answer your question from the title:
Yes there is a limit. It is shared with on_initialize such that on_initialize returns the weight for both on_initialize and on_finalize.

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.