事件日志记录

Vyper 可以将事件记录到用户界面以捕获和显示。

日志记录示例

此示例取自示例 ERC20 合约,并展示了事件日志记录的基本流程

# Events of the token.
event Transfer:
    sender: indexed(address)
    receiver: indexed(address)
    value: uint256

event Approval:
    owner: indexed(address)
    spender: indexed(address)
    value: uint256

# Transfer some tokens from message sender to another address
def transfer(_to : address, _value : uint256) -> bool:

   ... Logic here to do the real work ...

   # All done, log the event for listeners
   log Transfer(msg.sender, _to, _value)

让我们看看它是如何工作的。

  1. 我们声明两种事件类型以进行日志记录。这两个事件类似,因为它们都包含两个索引地址字段。索引字段不构成事件数据本身的一部分,但可以被想要捕获事件的客户端搜索。此外,每个事件都包含一个单一数据字段,在本例中分别称为value。事件可以包含多个具有任何所需名称的参数。

  2. transfer 函数中,在我们完成所有必要的工作之后,我们会记录该事件。我们传递三个参数,对应于 Transfer 事件声明的三个参数。

监听事件的客户端将使用诸如 web3.js 之类的库 来声明和处理它们感兴趣的事件。

var abi = /* abi as generated by the compiler */;
var MyToken = web3.eth.contract(abi);
var myToken = MyToken.at("0x1234...ab67" /* address */);

// watch for changes in the callback
var event = myToken.Transfer(function(error, result) {
    if (!error) {
        var args = result.returnValues;
        console.log('value transferred = ', args._amount);
    }
});

在此示例中,监听客户端声明了要监听的事件。只要合约发送此日志事件,就会调用回调函数。

声明事件

让我们更详细地了解事件声明。

event Transfer:
    sender: indexed(address)
    receiver: indexed(address)
    value: uint256

事件声明看起来类似于结构声明,包含一个或多个传递给事件的参数。典型的事件将包含两种参数

  • 索引参数,监听者可以搜索这些参数。每个索引参数都由indexed 关键字标识。在这里,每个索引参数都是一个地址。您可以拥有任意数量的索引参数,但索引参数不会直接传递给监听者,尽管监听者中的results 对象中可能提供一些信息(例如发送者)。

  • 参数,这些参数将传递给监听者。您可以拥有任意数量的值参数,并且它们可以具有任意的名称,但每个参数都受到 EVM 的限制,不能超过 32 字节。

也可以创建一个没有参数的事件。在这种情况下,请使用pass 语句

event Foo: pass

记录事件

声明事件后,您可以记录(发送)事件。您可以根据需要多次发送事件。请注意,发送的事件不会占用状态存储,因此不会消耗 gas:这使得事件成为保存某些信息的理想方式。但是,缺点是事件对合约不可用,仅对客户端可用。

记录事件是使用log 语句完成的

log Transfer(msg.sender, _to, _amount)

给定的参数的顺序和类型必须与声明事件时使用的参数顺序匹配。

监听事件

在上面的示例监听器中,result 参数实际上传递了大量信息。这里我们最感兴趣的是result.returnValues。这是一个包含与事件中声明的属性相匹配的属性的对象。请注意,此对象不包含索引属性,这些属性只能在创建回调函数的原始myToken.Transfer 中搜索。