Skip to content

Handlers simplification

Issue

Currently, the problem lies in having complicated handlers to follow, namely OnEvent. This handler has multiple paths hidden in several implementations, making it harder to read and account for weight. The OnIdty is on the same model but with fewer paths.

Current Design

Your implementation currently presents two designs for handlers:

  1. A loosely coupled approach where the handler is implemented in the runtime, and there is no tight coupling between dependencies.
  2. A tightly coupled approach where the handler is implemented inside one or more pallets, and dependencies are tightly coupled. These handlers are then assembled in a tuple handler, or in a (super) handler in the runtime that call these handlers.

At the moment, both approaches are used simultaneously, with OnEvent being implemented loosely in the runtime but also tightly inside the wot pallet (source).

Solution

There are multiple solutions to the problem:

  1. Splitting the OnEvent into smaller handlers, making them more comprehensible, following the model of OnNewcert and OnRemovecert.
  2. Implementing all handlers in a single implementation in the runtime, avoiding tuple handlers. This will make the pallets more flexible, avoiding tight couplings, but it can be counterintuitive for pallets like duniter-wot, where there is already a tight coupling with several pallets.

Note

In !246 (merged), Hugo mentioned decoupling the logic and the manual weight accounting that needs to be done for functions called in handlers and hooks. One way to achieve this is to separate the pallet into internal private functions with () or DispatchResult return type and public external functions with a Weight return type. I created a small POC crate where the weight can be autogenerated based on an expression or a function of the same argument signature, see example below. So, it is entirely possible to go this way with minimal work if the simplification mentioned above is not enough.

#[derive_weight(Weight::from_parts(10, 10))]
fn do_something(i: u32, j: u32) -> u32 {
     i * j
}
assert_eq!(weighted_do_something(1, 2), Weight::from_parts(10, 10));

//

fn weight_for_do_something(i: u32, _j: u32) -> Weight {
    if i == 0 {
        Weight::from_parts(10, 10)
    }
    else {
        Weight::from_parts(20, 20)
    }
 }
 #[derive_weight(weight_for_do_something)]
 fn do_something(i: u32, j: u32) -> u32 {
    if i == 0 {
        i + j
    }
    else {
        i/j
    }
 }
 assert_eq!(weighted_do_something(0, 2), Weight::from_parts(10, 10));
 assert_eq!(weighted_do_something(10, 2), Weight::from_parts(20, 20));

//

 #[derive_weight((Weight::zero(), Weight::from_parts(10, 10)))]
 fn do_something(i: u32, j: u32) -> Result<(), ()> {
    if i == 0 {
        Ok(())
    } else {
        Err(())
    }
 }
 assert_eq!(weighted_do_something(0), weight::from_parts(0, 0));
 assert_eq!(weighted_do_something(1), weight::from_parts(10, 10));
Edited by Benjamin Gallois
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information