Event Log
Event Log 是虚拟机的重要功能之一,用于在虚拟机运行合约过程中,输出特定二进制数据并记录在交易信息TransactionInfo中, Event Log可帮助开发人员确认,检查和快速检索智能合约的特定状态。本文介绍 Event 机制基础并介绍如何解码 Event Log 。
合约中如何定义和触发Event
使用Solidity语言编写合约时,通过 event
关键字定义Event,通过 emit
关键字触发 Event 。 在定义Event时,不仅可以指定事件名称,还可以指定若干参数,用来输出特定数据, 下面以TRC20合约的Transfer事件为例:
contract ExampleContractWithEvent {
event Transfer(address indexed from,address indexed to, uint256 value);
constructor() payable public{}
function contractTransfer(address toAddress, uint256 amount){
toAddress.transfer(amount);
emit Transfer(msg.sender,toAddress, amount);
}
}
event Transfer(address indexed from,address indexed to, uint256 value)
定义了一个名为Transfer的事件,包含三个参数,第一个是from
表示转账发起地址,第二个是to
表示转账目的地址,第三个是value
表示转账的数额emit Transfer(msg.sender,toAddress, amount)
指定在完成转账后,触发对应的Event,Event中包含转账发起地址,转账目的地址和转账金额。
注意:Solidity代码规范中,一般要求Event名字首字母大写,以区别于对应的函数。例如函数transfer和事件Transfer。
LOG
Solidity 使用 LOG 指令在交易信息TransactionInfo中记录事件信息。事件信息位于 TransactionInfo 的 log 字段,下面通过gettransactioninfobyid
API 获取到一个TransactionInfo来说明event的结构:
{
"id": "88c66d08f15b983183c7f7d23e3fafec0320bcc837d67957a8bda58d04ca53e1",
......
"log": [
{
"address": "a614f803b6fd780986a42c78ec9c7f77e6ded13c",
"topics": [
"ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"00000000000000000000000079309abcff2cf531070ca9222a1f72c4a5136874",
"00000000000000000000000081b64b1c09d448d25c9eeb3ee3b8f3348a694c96"
],
"data": "00000000000000000000000000000000000000000000000000000000b2d05e00"
}
]
}
log
: 交易中触发的Event列表,对于每一个Event,包含以下三部分内容:
address
: 合约地址。为了兼容EVM, 虚拟机中的地址为不带前缀0x41
的hex格式地址,因此如果要解析log中的地址,需要首先在log中的地址前面加上41
,然后再转换为Base58格式。topics
: 事件的主题,包括事件本身和标记为indexed
的参数。使用topics
保存indexed
参数的原因是:区块链储存一般会选择使用 LevelDB 或 RockDB 一类的 key-value 储存引擎。这些引擎一般都支持prefix-scan
操作,将indexed
参数放到topics
中,既可以快速检索Transfer
事件,又可以快速检索某一特定toAddress
的Transfer
事件。data
: 事件的非indexed
参数,例如amount
。
LOG 解码
对于上述LOG章节中的事件,想要对其解码,首先要知道合约中事件的ABI,下面是Transfer Event的ABI:
{
"anonymous":false,
"inputs":
[
{"indexed":true,"name":"from","type":"address"},
{"indexed":true,"name":"to","type":"address"},
{"indexed":false,"name":"value","type":"uint256"}
],
"name":"Transfer",
"type":"event"
}
将Event log与ABI对照来解码数据:
topics[0]
:ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef 是事件本身,该值为keccak256('Transfer(address,address,uint256)')
计算后的结果,因此该事件为Transfer事件。事件的keccak256哈希值可以通过tronweb.sha3()计算得到。注意:keccak256的参数为字符串,其中不能有任何空格,否则,计算出的哈希值将不同。topics[1]
:00000000000000000000000079309abcff2cf531070ca9222a1f72c4a5136874 是第一个indexed参数from
。这里的地址为去掉前缀0x41的20个字节地址,因此对于这个参数,拿到最后40位数据,再在前面加上41
就得到了TRON网络HEX格式地址。topics[2]
:00000000000000000000000081b64b1c09d448d25c9eeb3ee3b8f3348a694c96 是第二个indexed参数to
,接收者账户地址,解析同上。data
: 00000000000000000000000000000000000000000000000000000000b2d05e00 是非indexed参数的值,如果存在多个非indexed参数,则按照ABI编码规则依次列出,具体请参考ABI编码规则。对于这个例子,非indexed参数只有一个,即value
,转账数额,该数据为16进制数据,将其转为十进制即可。
Updated 10 months ago