上一篇文章介绍了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。 —- 编译者/作者:松果 玩币族申明:玩币族作为开放的资讯翻译/分享平台,所提供的所有资讯仅代表作者个人观点,与玩币族平台立场无关,且不构成任何投资理财建议。文章版权归原作者所有。 |
【Substrate开发教程】17 - Substrate声明事件宏decl_event!的使用
2020-10-31 松果 来源:区块链网络
LOADING...
相关阅读:
- 【昨日币乎1030】大宇为何常居热门和收入Top5,让我们从数据走进他2020-10-31
- 新闻周刊|区块链技术国家标准正加速制定2020-10-31
- 一周最少必要关注丨paypal 可以买比特币了;币安惹什么事了?2020-10-31
- 达客大数据中心签约青云谱区2020年“高质量转型升级”2020-10-31
- 雷凯趋势:比特币日内操作思路逢高做空2020-10-31