0

I am having trouble understanding the verification process for storage changes that are applied during the on_initialize hooks of a pallet. From what I understand, imported blocks do not re-run any process that occurs in the hooks, so how do "importers" confirm that they accept the changes that are made outside of an extrinsic?

For instance, in Kulupu, the rewards are delegated through the on_finalize process:

fn on_finalize(now: T::BlockNumber) {
    if let Some(author) = <Self as Store>::Author::get() {
        let reward = Reward::<T>::get();
        Self::do_reward(&author, reward, now);
    }

    let mints = Mints::<T>::get();
    Self::do_mints(&mints);

    <Self as Store>::Author::kill();
}
    
fn do_mints(mints: &BTreeMap<T::AccountId, BalanceOf<T>>) {
    for (destination, mint) in mints {
        drop(T::Currency::deposit_creating(&destination, *mint));
    }
}

I don't see anywhere in that codebase that's checking what rewards a given node gave to an author.

1 Answer 1

0

From what I understand, imported blocks do not re-run any process that occurs in the hooks

I'm not sure if I follow you here but every validator will run the runtime hooks logic when they validate/apply a block (ref).

how do "importers" confirm that they accept the changes that are made outside of an extrinsic?

Do they confirm the changes coming from applying extrinsics? They simply apply the block if everything is valid; valid extrinsics, valid blockbuilder, etc. If they don't apply them and more than 2/3 of the network does, it either has to leave the network or comply with the state of the blockchain and continue.

I don't see anywhere in that codebase that's checking what rewards a given node gave to an author.

How is this checked within an extrinsic? All the validators just run the state transition function (runtime code) which the hooks are a part of.

The only way to give different rewards in the hooks (referring to your example) is to have a different state transition function (this also counts for extrinsics). And because the state transition function is part of the state, the state (root) will always be different for this malicious validator. As a result, this validator will never be able to build a valid block or validate a block.

Last, all information you request can be verified. Pieces of data provided by (rpc) nodes are supported with a merkle proof. The 'caller' can simply verify the response with the valid state and block header it has, either by running a full node or light client.

4
  • Since it's a decentralized network, shouldn't the expectation be that someone will in fact change the code and also change their version of substrate not to modify the runtime hash/state root? Is this somehow cryptographically ensured?
    – blakeb
    Aug 23, 2023 at 13:56
  • I edited my answer, please let me know if something is still unclear Aug 23, 2023 at 15:18
  • Super helpful! Thank you! Ok, I had read a few times that the hooks logic wasn't followed during import, which made it very confusing to understand how the state changes would apply the same way for all nodes. To re-state what you're saying, all nodes replay the full extent of the changes and the resulting state changes must match, or they won't accept the block?
    – blakeb
    Aug 23, 2023 at 15:58
  • That is correct Aug 24, 2023 at 7:12

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.