mountbranch
mountbranch

Reputation: 344

What's the function of `<T>` in Substrate's `fn deposit_event<T>() = default`?

In reference to the Substrate Collectables Workshop, what does the <T> actually do and refer to in fn deposit_event<T>() = default;? Can I omit it when my Event doesn't include for example AccountId?

Upvotes: 0

Views: 488

Answers (1)

Shawn Tabrizi
Shawn Tabrizi

Reputation: 12434

In the context of Substrate, there are a few things to answer here.

Generic Types

Each Substrate module has the ability to define the custom types needed for the module, all of which are required to implement some traits. Rather than strongly defining these types, using traits allows us to ensure that the types have certain properties, but are not limited in what the type can be. These generic type definitions live in trait Trait, which must be defined in each module.

Here is an example of the custom types defined in the system module, which is used in nearly all other modules:

pub trait Trait: 'static + Eq + Clone {
    /// The aggregated `Origin` type used by dispatchable calls.
    type Origin: ...

    /// Account index (aka nonce) type. This stores the number of previous transactions associated with a sender
    /// account.
    type Index: ...

    /// The block number type used by the runtime.
    type BlockNumber: ...

    /// The output of the `Hashing` function.
    type Hash: ...

    /// The hashing system (algorithm) being used in the runtime (e.g. Blake2).
    type Hashing: Hash<Output = Self::Hash>;

    /// Collection of (light-client-relevant) logs for a block to be included verbatim in the block header.
    type Digest: ...

    /// The user account identifier type for the runtime.
    type AccountId: ...

    /// Converting trait to take a source type and convert to `AccountId`.
    ///
    /// Used to define the type and conversion mechanism for referencing accounts in transactions. It's perfectly
    /// reasonable for this to be an identity conversion (with the source type being `AccountId`), but other modules
    /// (e.g. Indices module) may provide more functional/efficient alternatives.
    type Lookup: StaticLookup<Target = Self::AccountId>;

    /// The block header.
    type Header: ...

    /// The aggregated event type of the runtime.
    type Event: Parameter + Member + From<Event>;

    /// A piece of information that can be part of the digest (as a digest item).
    type Log: From<Log<Self>> + Into<DigestItemOf<Self>>;
}

In your custom module, you will define something like:

/// The module's configuration trait.
pub trait Trait: system::Trait {
    /// The overarching event type.
    type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
}

Note here that we have defined our own Event type, which our module can now use, but also we have inherited the traits from the system module (system::Trait), so we can also use all those types too!

Using Generic Types

Now that we have defined some custom types in our runtime module, we can start to use them throughout our module logic.

You will always see a line like the second line in this code snippet:

decl_storage! {
    trait Store for Module<T: Trait> as Sudo {
        /// The `AccountId` of the sudo key.
        Key get(key) config(): T::AccountId;
    }
}

Some of this line is macro magic, but importantly you see we define Module<T: Trait>. This means we have assigned our module's trait Trait as the generic parameter for Module under the alias of T.

Thus, we can then use T to reference these special types like we did above:

T::AccountId

Going full circle, we can access this type because we have inherited it from the system::Trait definition!

Deposit Event Macro Generation

To finally answer your question, the decl_module! function generates the function body of the deposit_event to save you from writing the same code over and over.

We detect the pre-defined function name deposit_event, and check for = default;, and then replace that with a working deposit_event function.

However, when generating this function, the macro does not know if it should use a function where the input event is generic, or the input event does not use generics. Thus, you need to "give it a hint" by saying deposit_event<T>() or just deposit_event().

It will then produce the right version of the function which will work with the types in your module. If your module events uses any generic types, like T::AccountId or T::Balance, you will also need to define the generic version of deposit_event.

Upvotes: 4

Related Questions