LOADING...
LOADING...
LOADING...
当前位置: 玩币族首页 > 区块链资产 > 【Substrate开发教程】17 - Substrate声明事件宏decl_event!的使用

【Substrate开发教程】17 - Substrate声明事件宏decl_event!的使用

2020-10-31 松果 来源:区块链网络


上一篇文章介绍了decl_storage!宏的使用,这篇介绍Substrate runtime开发中另一个重要的宏decl_event!,它用于声明模块函数会触发的事件。

事件(Event)

事件(Event)是一种通知机制,可以通知链外世界链上的状态转换是否成功,事件需要在模块函数中触发。

像任何Rust枚举(enum)类型一样,Event都有名称并且可以携带数据。

将交易包含在区块中并不能保证函数成功执行,要验证函数是否成功执行需要使用事件。

据根事件携带的数据是基本数据类型还是来自pallet配置的通用数据类型,声明Event的语法略有不同,具体可分为:

简单事件(simple event)通用事件(generic event)

配置Event

要使用事件,需要在Trait中配置Event类型。

配置简单事件:

pub trait Trait: frame_system::Trait { type Event: From<Event> + Into<<Self as frame_system::Trait>::Event>; }

配置通用事件:

pub trait Trait: frame_system::Trait { type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>; }

这里的语法看起来比较复杂,但配置Event时每次都是一样的代码,直接复制即可。

接下来需要在decl_module!宏添加一行代码,声明存储事件的函数:

fn deposit_event() = default;

这句代码是decl_module!宏特有的,每次直接复制即可。

声明Event

声明事件使用decl_event!宏。

声明一个简单事件:

decl_event!( pub enum Event { EmitInput(u32), } );

声明一个通用事件:

decl_event!( pub enum Event<T> where AccountId = <T as frame_system::Trait>::AccountId { EmitInput(AccountId, u32), } );

这里展示了where子句如何为更具可读性的代码指定类型别名。

触发事件

在decl_module!中调用deposit_event函数来触发事件。

事件不会在创世区块上触发,创世区块形成期间进行的任何函数调用都不会发出事件。

触发简单事件:

Self::deposit_event(Event::EmitInput(new_number));

触发通用事件:

Self::deposit_event(RawEvent::EmitInput(user, new_number));

这里deposit_event的参数使用RawEvent类型,是因为它在模块配置上是通用的。

构造Runtime

上一篇文章介绍了runtime/src/lib.rs对于每个模块都有的处理流程:

1、导入包含该模块的Rust文件;2、实现其Trait;3、将该模块包含在construct_runtime!宏中;

如果模块中使用了Event,第2步实现其Trait时需要定义Event类型:

impl simple_event::Trait for Runtime { type Event = Event; }

第3步也需要添加Event类型,对于简单事件:

TemplateModule: pallet_template::{Module, Call, Event},

对于通用事件:

TemplateModule: pallet_template::{Module, Call, Event<T>},

注意通用事件比简单事件多了一个范型<T>。

编写模块代码

修改pallets/template/src/lib.rs的代码如下:

#![cfg_attr(not(feature = "std"), no_std)] use frame_support::{decl_module, decl_event, dispatch::DispatchResult}; use frame_system::{ensure_signed}; pub trait Trait: frame_system::Trait { type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>; } decl_event!( pub enum Event<T> where AccountId = <T as frame_system::Trait>::AccountId { EmitInput(AccountId, u32), } ); decl_module! { pub struct Module<T: Trait> for enum Call where origin: T::Origin { fn deposit_event() = default; #[weight = 10_000] fn do_something(origin, input: u32) -> DispatchResult { let user = ensure_signed(origin)?; let new_number = input + 100; Self::deposit_event(RawEvent::EmitInput(user, new_number)); Ok(()) } } }

编译

编译命令如下:

cd substrate-node-template cargo +nightly-2020-08-23 build --release

使用了nightly-2020-08-23这个较稳定的cargo nightly版本以避免编译过程中出现bug。


测试

启动node-template

./target/release/node-template --dev

打开https://polkadot.js.org/apps,切换网络为DEVELOPMENT-Local Node:


选项卡选择开发者-交易,“提交下面的外部信息”选择templateModule,会自动获取到定义的函数doSomething(input):


可以设置函数参数input的值,这里我设置了100。

点击右下角“提交交易”按钮,点击“签名并提交”:


就会调用decl_module!中定义的do_something函数,此函数将原值加100,并触发事件。

选项卡选择网络-浏览-链信息,在右侧可以看到最新触发的事件:


可以看到触发的事件是模块代码中定义的templateModule.EmitInput,返回的值是200。

—-

编译者/作者:松果

玩币族申明:玩币族作为开放的资讯翻译/分享平台,所提供的所有资讯仅代表作者个人观点,与玩币族平台立场无关,且不构成任何投资理财建议。文章版权归原作者所有。

LOADING...
LOADING...