All pages
Powered by GitBook
1 of 7

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Runtime Storage

Runtime Configuration Trait

The configuration trait is a way for you to allow external pallets to define the element types being used on your internal pallet.

substrate_ is taking full advantage of the extensibility features of Rust by implementing the Config object as a trait.

The best practice when building your pallet is to implement Generic Types.

This will allow you to create all the functionality you want while leaving the concrete types a decision made at runtime.

The Configutation Trait is the way that substrate_ empowers the use of that extensible framework writing.

The Configuration Trait definition is a requirement for all pallets.

Hook

FRAME Pallet

FRAMPallets are individual pieces of runtime logic for us in FRAME runtimes.

substrate_ has a long list of pre-packages pallets, but you can also build your own or modify one built by the substrate_ team.

Pallet Structure

A pallet is composed of a few building blocks. These are:

Imports

The most critical imports for every Pallet

frame_system provides low-level types, storage, and functions for your blockchain.

frame_support is like a helper crate. It is a collection of macros, traits, and modules to simplify development of FRAME Pallets.

The frame_executive acts as an orchestration layer for the runtime. It dispatches incoming extrinsic calls to the respective pallets in runtime.

Extrinsics (Dispatchable Calls)

These are the public endpoints you are giving to users to interact with the blockchain.

Dispatchable calls are the public endpoints you expose for users so they can interact with your blockchain.

Dispatchable calls must be included on every .

📡frame_system
🤝frame_support
🤠frame_executive
pallet
  • Declaration of Pallet Type

  • Runtime Configuration Trait

  • Runtime Storage

  • Runtime Events

  • Hooks

  • Extrinsics (Dispatchable Calls)

  • No Std

    The first line of code, always. It tells the rust compiler not to use Rust's standard library except when explicitly told so.

    Substrate runtimes are compiled to WASM and a regular native binary so you do not have access to rust's standard library.

    This means simple things like printing to the command line using println! will not compile.

    Learn more here.

    Imports

    This is where crates are imported, especially the substrate_ framework crates.

    All pallets will import frame-support and frame-system

    Declaration of the Pallet Type

    A placeholder to implement traits and methods.

    Runtime Configuration Trait

    This is used to access features from other pallets, or constants that impact the pallet's behavior.

    This is the part of the code where you say "hey I'm going to create some functions that do with something I'll call coin and I'm going to have the be the coin that's defined in the other pallet....but I'm going to also cast votes, so my votes will be the ones defined in that other voting pallet"

    The Config trait allows you to do the above while keeping Generic Types so you can change define and use something called coin or votes from some other Pallet defined at runtime, but swapped with some other pallet with a runtime update later on.

    Runtime Storage

    Have some custom data you want on the chain for users or otherwise?

    Runtime Storage is where you do that. You declare storage items you'd like to make accessible to runtime.

    Runtime Events

    Events are how you communicate back to people using the block chain like "transaction confirmed!" or "error! not enough cash!"

    Hooks

    This is where you'd build some logic that can be executed regularly in some context, for e.g. on_initialize.

    Basically, your blockchain's equivalent to handling webhooks.

    Extrensics (Dispatchable Calls)

    These are functions that blockchain users can call. This is often called a Dispatchable Call.

    decl_module!

    This is the macro where dispatchable calls are composed.

    A Little More on Each Topic

    Imports
    ⬇️Imports
    ⚙️Runtime Configuration Trait
    💾Runtime Storage
    👍Runtime Events
    🏑Hook
    🙋Extrinsics (Dispatchable Calls)
    pub use pallet::*;
    // other global dependencies...
    
    #[frame_support::pallet]
    pub mod pallet {
        use frame_support::pallet_prelude::*;
        use frame_system::pallet_prelude::*;
        // other pallet dependencies...
        #[pallet::pallet]
        #[pallet::generate_store(pub(super) trait Store)]
        #[pallet::generate_storage_info]
        pub struct Pallet<T>(_);

    Runtime Events

    How to tell someone using your blockchain something happened.

    Users of the application need feedback about what happened when they clicked something or interacted on your chain through a public endpoint you've given them.

    Transactions can fail for any number of reasons, so your users need to know and that is handled through and Event. Confirmations are similar: tell your user it went okay with an Event.

    Right, so my pallet should be able to emit Events?

    Yep, pretty much without exception. Here's how:

    In the Pallet

    type Event

    Add Event type to the `Config:

    decl_module!

    And now add the decl_module! ("declare_module") macro to give access to the deposit_event() method.

    Reminder: the decl_module! macro is the same we used for creating Dispatchable Calls for a Pallet.

    decl_event!

    decl_event! ("declare event") macro is the way Rust implements an event

    We are showing generic types in these examples. The syntax for generic events requires the where.

    In the Runtime

    We've defined a trait in the Pallet for Config and so now it has to be implemented at runtime.

    In your runtime lib.rs file, add

    The code above is simply specifying the type for Event . Note the <T> is not shown and that is because we are defining the concrete type to be implemented by the Pallet we're configuring.

    Add the events to the runtime build macro construct_runtime! by adding:

    // Note: this is the pallet-required `Configuration Trait`
    pub trait Config: frame_system::Config {
        
        // copy the line below exactly as shown into the `Config` section
        // of your `Pallet`. You'll eventually be able to interpret that
        // if you don't lnow. Just keep truckin'.
        type Event: From<Event> + Into<<Self as frame_system::Config>::Event>;
    
    }
    decl_module! {
    pub struct Module<T: Config> for enum Call where origin: T::Origin {
    
        // This line is new
        fn deposit_event() = default;
    
        // More dispatchable calls that you compose woud go here
        }
    }
    decl_event!(
        pub enum Event<T> where AccountId = <T as frame_system::Config>::AccountId {
            EmitInput(AccountId, u32),
        }
    );
    ./runtime/src/lib.rs
    impl simple_event::Config for Runtime {
        type Event = Event;
    }
    construct_runtime!(
        pub enum Runtime where
            Block = Block,
            NodeBlock = opaque::Block,
            UncheckedExtrinsic = UncheckedExtrinsic
        {
            // --snip--
            YourEventName: your_pallet_name,
        }
    );