跳转到内容

事件

事件在交易执行期间发出。每个 Move 模块都可定义自己的事件,并决定在模块执行时何时发出事件。Aptos Move 支持两种事件:模块事件和 EventHandle 事件。模块事件是现代事件机制,随 framework 1.7 版本发布;EventHandle 事件已弃用,随最初的 framework 一同发布。受区块链的工作方式影响,EventHandle 事件很可能永远无法从 Aptos 中彻底移除。

模块事件是通过结构体类型标识的全局事件流。要定义事件结构体,请为拥有 dropstore 能力的普通 Move 结构体添加 #[event] 属性。例如:

/// 0xcafe::my_module_name
/// An example module event struct denotes a coin transfer.
#[event]
struct TransferEvent has drop, store {
sender: address,
receiver: address,
amount: u64
}

然后创建并发出该事件:

// Define an event.
let event = TransferEvent {
sender: 0xcafe,
receiver: 0xface,
amount: 100
};
// Emit the event just defined.
0x1::event::emit(event);

可在此处查看示例模块事件。索引 0、1、2 是类型为 0x66c34778730acbb120cefa57a3d98fd21e0c8b3a51e9baee530088b2e444e94c::event::MyEvent 的三个模块事件。为保持 API 兼容性,模块事件包含 Account AddressCreation NumberSequence Number 字段,且它们均为 0。

模块事件示例

每笔交易的事件都存储在称为事件累加器的独立 Merkle 树中。由于它是临时的且独立于状态树,MoveVM 在生产环境执行交易时无法读取事件。但在测试中,Aptos Move 支持两个原生函数,可读取已发出的事件以进行测试和调试:

/// Return all emitted module events with type T as a vector.
# [test_only]
public native fun emitted_events<T: drop + store>(): vector<T>;
/// Return true iff `msg` was emitted.
# [test_only]
public fun was_event_emitted<T: drop + store>(msg: & T): bool

可通过 GraphQL API 查询模块事件和 EventHandle 事件。

作为遗留机制,Aptos 继承了源自 EventHandle 的 Libra/Diem 事件流。每个 EventHandle 通过全局唯一值 GUID 和每事件序列号进行标识,并存储在资源中。事件流中的每个事件都拥有从 EventHandle 序列号派生的唯一序列号。

例如,在进行代币转账时,发送方和接收方账户都会分别发出 SentEventReceivedEvent。这些数据存储在账本中,可通过 REST 接口的按事件句柄获取事件查询。

假设账户 0xc40f1c9b9fdc204cf77f68c9bb7029b0abbe8ad9e5561f7794964076a4fbdcfd 已向另一账户发送代币,可对 REST 接口发出以下查询:https://api.devnet.aptoslabs.com/v1/accounts/c40f1c9b9fdc204cf77f68c9bb7029b0abbe8ad9e5561f7794964076a4fbdcfd/events/0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>/withdraw_events。输出为该账户存储的所有 WithdrawEvent,如下所示:

[
{
"key": "0x0000000000000000caa60eb4a01756955ab9b2d1caca52ed",
"sequence_number": "0",
"type": "0x1::coin::WithdrawEvent",
"data": {
"amount": "1000"
}
}
]

每个已注册事件都有唯一 key。键 0x0000000000000000caa60eb4a01756955ab9b2d1caca52ed 映射到账户 0xc40f1c9b9fdc204cf77f68c9bb7029b0abbe8ad9e5561f7794964076a4fbdcfd 上注册的事件 0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>/sent_events。随后可用此键直接发出事件查询,例如 https://api.devnet.aptoslabs.com/v1/events/0x0000000000000000caa60eb4a01756955ab9b2d1caca52ed

这些是事件流,即由事件组成的列表;每个条目包含从 0 开始顺序递增的 sequence_numbertypedata。每个事件都必须由某种 type 定义;尤其在使用泛型时,可能有多个事件由相同或相似的 type 定义。事件关联 data。一般原则是:应包含在改变数据并发出事件的交易执行前后,理解底层资源变化所需的全部数据。

随着模块事件发布,EventHandle 事件已弃用。为支持迁移到模块事件,项目应在当前发出 EventHandle 事件的每个位置同时发出模块事件。当外部系统充分采用模块事件后,可能不再需要发出旧事件。

注意,EventHandle 事件无法也不会被删除;因此无法升级的项目仍可继续使用它们。