【区块链安全 | 第二十九篇】合约(三)

在这里插入图片描述

合约

事件(Events)

Solidity 中的事件是对 EVM 日志功能的抽象封装。应用程序可以通过以太坊客户端的 RPC 接口订阅和监听这些事件。

事件可以在文件级别定义,或作为合约(包括接口和库)的可继承成员定义。当事件被触发时,其参数会被记录在交易的日志(log)中 —— 区块链上的一种特殊数据结构。这些日志与触发事件的合约地址相关联,包含在区块链中,并会一直保留,只要区块仍可访问(目前是永久保留,但未来可能会改变)。日志及事件数据在合约内部不可访问(即使是触发该事件的合约本身也不行)。

日志可以请求 Merkle 证明,因此如果外部实体向合约提供此类证明,合约可以验证该日志确实存在于区块链中。但由于合约只能访问最近 256 个区块的哈希,因此必须提供区块头信息。

你可以给最多三个事件参数添加 indexed 属性,使它们被加入到称为“主题(topics)”的特殊数据结构中,而不是日志的 data 部分。每个 topic 只能保存一个 word(32 字节),因此如果为引用类型参数加上 indexed,将存储其 Keccak-256 哈希值

没有 indexed 修饰的参数,会被 ABI 编码后存入日志的 data 部分。

使用 topics 可以方便地筛选事件,例如从一系列区块中过滤出特定事件。你还可以通过合约地址过滤事件。

例如,以下代码使用 web3.js 的 subscribe("logs") 方法,按特定地址匹配某个 topic:

var options = {
   
    
    
    fromBlock: 0,
    address: web3.eth.defaultAccount,
    topics: ["0x0000000000000000000000000000000000000000000000000000000000000000", null, null]
};
web3.eth.subscribe('logs', options, function (error, result) {
   
    
    
    if (!error)
        console.log(result);
})
    .on("data", function (log) {
   
    
    
        console.log(log);
    })
    .on("changed", function (log) {
   
    
    
});

事件的 函数签名哈希 是默认写入 topics 的一项,除非你在声明事件时使用了 anonymous 关键字。也就是说:

  • 非匿名事件 可以通过事件签名筛选;
  • 匿名事件 无法通过事件名筛选,只能按合约地址筛选;
  • 但匿名事件的好处是:部署和调用成本更低,并且允许使用 4 个 indexed 参数(非匿名最多只能用 3 个)。

注意:由于交易日志仅存储事件数据,而不记录其类型信息,因此你必须清楚事件的结构,才能正确解析日志。这包括哪些参数是 indexed&#

猜你喜欢

转载自blog.csdn.net/2301_77485708/article/details/147036480