6

I need to be sure that the on_initialize handler for a specific module runs before the same handler before all other modules in my runtime.

a) How do ensure this?

b) Is there some compile or runtime check I can enforce to absolutely guarantee that this will be respected?

Shawn Tabrizi
  • 12,206
  • 1
  • 38
  • 69
Bedeho Mender
  • 211
  • 1
  • 3

1 Answers1

9

The on_initialize function for each Substrate runtime module is called via the Executive module, which handles all of the top-level stuff; essentially just executing blocks/extrinsics.

Every time a block is executed (execute_block), first initialize_block is called which ultimately calls the on_initalize block for the AllModules type:

srml/executive/src/lib.rs

<AllModules as OnInitialize<System::BlockNumber>>::on_initialize(*block_number);

The AllModules type is a tuple of the different module identifiers in your runtime. It generated by the construct_runtime! macro and lists the modules in the order you defined them in the macro.. For example, for the given construct_runtime! definition:

construct_runtime!(
    pub enum Runtime with Log(InternalLog: DigestItem<Hash, AuthorityId, AuthoritySignature>) where
        Block = Block,
        NodeBlock = opaque::Block,
        UncheckedExtrinsic = UncheckedExtrinsic
    {
        System: system::{default, Log(ChangesTrieRoot)},
        Timestamp: timestamp::{Module, Call, Storage, Config<T>, Inherent},
        Consensus: consensus::{Module, Call, Storage, Config<T>, Log(AuthoritiesChange), Inherent},
        Aura: aura::{Module},
        Indices: indices,
        Balances: balances,
        Sudo: sudo,
        // Used for the module template in `./template.rs`
        TemplateModule: template::{Module, Call, Storage, Event<T>},
        TemplateModule1: template1::{Module, Call, Storage, Event<T>},
        TemplateModule2: template2::{Module, Call, Storage, Event<T>},
    }
);

You will get the following AllModules type:

type AllModules = (Timestamp, Consensus, Aura, Indices, Balances, Sudo, TemplateModule, TemplateModule1, TemplateModule2);

Thus, the on_initialize function is called in order which you define the modules in your runtime. There is nothing you need to do to "ensure this will be respected", since code flow is serial and deterministic here.

Shawn Tabrizi
  • 12,206
  • 1
  • 38
  • 69
  • Great answer! By ensure, I mean that it is not possible for a developer to accidentally construct the runtime while having a different order. The main thing we are now considering is to instead use a safer wrapper macro `construct_migrating_runtime(, `) which makes sure to add the module first no matter what. – Bedeho Mender Jun 21 '19 at 10:19
  • Yes, you would need to bake in your own custom logic, and I guess there would be a million ways to do it. One such example is only have one `on_initialize` hook from the first module, and then it calls the next one by a specific function name, and so on. – Shawn Tabrizi Jun 21 '19 at 10:23
  • Documentation would also help here, it seems pretty necessary in general for creating modules which will be used by others. – Shawn Tabrizi Jun 21 '19 at 15:34