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.
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.
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 .
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.
This is where crates are imported, especially the substrate_ framework crates.
All pallets will import frame-support and frame-system
A placeholder to implement traits and methods.
This is used to access features from other pallets, or constants that impact the pallet's behavior.
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.
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.
Events are how you communicate back to people using the block chain like "transaction confirmed!" or "error! not enough cash!"
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.
These are functions that blockchain users can call. This is often called a Dispatchable Call.
This is the macro where dispatchable calls are composed.
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>(_);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.
Yep, pretty much without exception. Here's how:
Add Event type to the `Config:
And now add the decl_module! ("declare_module") macro to give access to the deposit_event() method.
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.
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),
}
);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,
}
);