You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CryptoZombies第1课13章Solidity事件概念及代码解析求助

Solidity事件(Events)核心概念与示例代码逐段讲解

事件核心概念

Solidity的事件是EVM提供的合约与链下系统通信的原生能力,核心特性如下:

  • 事件触发后会将携带的参数打包写入对应交易的链上日志,日志与合约地址永久绑定,可被链上节点校验,但合约自身无法读取历史日志
  • 日志写入的gas成本远低于合约状态存储,适合做链上动作的通知载体
  • 链下服务(DApp前端、链下索引程序、脚本)可以订阅指定合约的指定事件,事件触发后会实时收到推送,不需要持续轮询链上数据
  • 事件参数可以加indexed修饰符,支持链下服务按参数值过滤检索对应日志,本次示例为事件基础用法,未使用该修饰符

逐段代码拆解

示例完整代码如下:

pragma solidity >=0.5.0 <0.6.0;

contract ZombieFactory {

    event NewZombie(uint zombieId, string name, uint dna);

    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;

    struct Zombie {
        string name;
        uint dna;
    }

    Zombie[] public zombies;

    function _createZombie(string memory _name, uint _dna) private {
        uint id = zombies.push(Zombie(_name, _dna)) - 1;
        emit NewZombie(id, _name, _dna);
    }

    function _generateRandomDna(string memory _str) private view returns (uint) {
        uint rand = uint(keccak256(abi.encodePacked(_str)));
        return rand % dnaModulus;
    }

    function createRandomZombie(string memory _name) public {
        uint randDna = _generateRandomDna(_name);
        _createZombie(_name, randDna);
    }

}

逐段逻辑说明:

  • pragma solidity >=0.5.0 <0.6.0;
    编译器版本声明,限定合约只能使用0.5.x系列版本的Solidity编译器编译,避免不同版本语法不兼容导致的编译错误。
  • contract ZombieFactory {
    声明名为ZombieFactory的合约,所有合约逻辑都包裹在该合约的作用域内。
  • event NewZombie(uint zombieId, string name, uint dna);
    事件定义,语法和函数签名类似:指定事件名为NewZombie,触发时需要传入3个参数,分别为新僵尸的ID、名称、DNA值。事件定义必须放在合约顶层,不能嵌套在函数内部。
  • uint dnaDigits = 16;、uint dnaModulus = 10 ** dnaDigits;
    两个合约状态变量,dnaDigits定义僵尸DNA固定为16位长度,dnaModulus取值为10的16次方,后续生成随机DNA时取模用,保证生成值不超过16位。
  • struct Zombie { string name; uint dna; }
    自定义Zombie结构体,每个僵尸实例包含两个属性:字符串类型的名称、无符号整数类型的DNA值。
  • Zombie[] public zombies;
    声明Zombie类型的公开动态数组,用于存储所有生成的僵尸实例;public修饰符会自动为该数组生成同名查询函数,外部可传入索引值查询对应位置的僵尸数据。
  • function _createZombie(string memory _name, uint _dna) private { ... }
    私有内部函数,函数名以下划线开头是Solidity社区约定的私有函数命名规范,仅允许合约内部调用,外部无法直接访问:
    • 参数_name、_dna用memory修饰,指定参数临时存储在内存中,不写入链上状态
    • uint id = zombies.push(Zombie(_name, _dna)) - 1;:向zombies数组末尾推入一个新的僵尸实例,Solidity 0.5版本中数组push方法返回数组更新后的长度,减1即为新插入僵尸在数组中的索引ID(数组索引从0开始计数)
    • emit NewZombie(id, _name, _dna);:事件触发逻辑,使用emit关键字调用之前定义的NewZombie事件,传入新僵尸的ID、名称、DNA三个参数;该逻辑执行时会将参数打包写入交易日志,不会修改合约自身的状态变量,gas成本远低于状态写入。
  • function _generateRandomDna(string memory _str) private view returns (uint) { ... }
    私有视图函数,不修改链上状态,传入一个字符串返回无符号整数作为随机DNA:
    • 将传入的字符串通过abi.encodePacked打包后,用keccak256算法计算得到256位哈希值,强转为无符号整数
    • 将哈希值对dnaModulus取模,得到16位长度的数值作为DNA返回
  • function createRandomZombie(string memory _name) public { ... }
    公开函数,是外部用户调用创建僵尸的唯一入口:
    • 传入想要设置的僵尸名称,内部先调用_generateRandomDna基于名称生成随机DNA
    • 再调用_createZombie将新僵尸存入数组,同时触发NewZombie事件

示例中事件的完整执行链路

  1. 用户向合约地址发送交易,调用createRandomZombie函数传入僵尸名称
  2. EVM执行合约逻辑,生成随机DNA、将新僵尸存入zombies数组
  3. 执行到emit语句时,将新僵尸的ID、名称、DNA写入交易日志
  4. 交易被打包确认上链后,所有订阅了该合约NewZombie事件的链下服务会实时收到事件携带的参数,前端即可直接更新页面展示新生成的僵尸,不需要反复轮询链上查询状态变化

内容的提问来源于stack exchange,提问作者jerome richard A R

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 13:15:35