特性——事件

Seven 2022-01-04 17:01:44
Categories: > Tags:

事件是智能合约发出的信号。智能合约的前端UI,例如,DApps、web.js,或者任何与Ethereum JSON-RPC API连接的东西,都可以侦听这些事件。事件可以被索引,以便以后可以搜索事件记录。

1
2
事件在区块链中的存储
区块链是一个区块链表,这些块的内容基本上是交易记录。每个交易都有一个附加的交易日志,事件结果存放在交易日志里。合约发出的事件,可以使用合约地址访问。

Solidity 事件

Solidity中,要定义事件,可以使用event关键字(在用法上类似于function关键字)。然后可以在函数中使用emit关键字触发事件。

1
2
3
4
5
// 声明一个事件
event Deposit(address indexed _from, bytes32 indexed _id, uint _value);

// 触发事件
emit Deposit(msg.sender, _id, msg.value);

示例

创建合约并发出一个事件。

1
2
3
4
5
6
7
8
9
10
11
12
pragma solidity ^0.5.0;

contract Counter {
uint256 public count = 0;

event Increment(address who); // 声明事件

function increment() public {
emit Increment(msg.sender); // 触发事件
count += 1;
}
}

上面的代码中,

按照惯例,事件名称以大写字母开头,以区别于函数。

用JavaScript监听事件

下面的JavaScript代码侦听Increment事件,并更新UI。

1
2
3
4
5
6
7
8
9
10
11
12
counter = web3.eth.contract(abi).at(address);

counter.Increment(function (err, result) {
if (err) {
return error(err);
}

log("Count was incremented by address: " + result.args.who);
getCount();
});

getCount();
索引(indexed)参数

一个事件最多有3个参数可以标记为索引。可以使用索引参数有效地过滤事件。下面的代码增强了前面的示例,来跟踪多个计数器,每个计数器由一个数字ID标识:

1
2
3
4
5
6
7
8
9
10
11
12
pragma solidity ^0.4.21;

contract Multicounter {
mapping (uint256 => uint256) public counts;

event Increment(uint256 indexed which, address who);

function increment(uint256 which) public {
emit Increment(which, msg.sender);
counts[which] += 1;
}
}

在Javascript中,可以使用索引访问计数器:

1
2
3
4
5
6
7
8
9
counter.Increment({ which: counterId }, function (err, result) {
if (err) {
return error(err);
}

log("Counter " + result.args.which + " was incremented by address: "
+ result.args.who);
getCount();
});
事件的局限

事件构建在Ethereum中,底层的日志接口之上。虽然您通常不会直接处理日志消息,但是了解它们的限制非常重要。

日志结构最多有4个“主题”和一个“数据”字段。第一个主题用于存储事件签名的哈希值,这样就只剩下三个主题用于索引参数。主题需要32字节长,因此,如果使用数组作为索引参数(包括类型string和bytes),那么首先将哈希值转换为32字节。非索引参数存储在数据字段中,没有大小限制。

日志,包括记录在日志中的事件,不能从Ethereum虚拟机(EVM)中访问。这意味着合约不能读取自己的或其他合约的日志及事件。

总结

附言

基础学习资料

与智能合约交互

源码

示例项目

调试工具