修饰器 modifier

本章学习 Solidity 修饰器 modifier 的定义和使用方法。

视频Bilibili  |  Youtube
官网binschool.app
推特@BinSchool    DiscordBinDAO   微信:bkra50 

Solidity 中,修饰器是一种用于修改函数行为的语法结构。当修饰器作用于一个函数上,可以在该函数运行前或者运行后,执行修饰器中的逻辑,以增强其功能。

修饰器在智能合约中使用非常普遍,常常用于验证输入参数、执行权限检查、记录日志等操作。通过使用修饰器,可以在不改变函数本身逻辑的情况下,对函数进行重用和扩展。

1. 定义语法

Solidity 使用关键字 modifier 声明一个函数修饰器,语法如下:

modifier modifier-name(parameter1, parameter2, ...) {
    // 在函数执行前执行的逻辑
    _; // 执行被修饰的函数
    // 在函数执行后执行的逻辑
}

修饰器语法中包含以下部分:

    • modifier

关键字,用于声明一个修饰器。

    • modifier-name

修饰器的名称,可以根据需求自定义。

    • (parameter1, parameter2, ...)

可选的修饰器参数列表,用于传递参数给修饰器。

    • 修饰器逻辑

在被修饰函数执行之前和之后执行的逻辑。

    • 特殊符号 _

_ 表示被修饰函数的执行位置。

2. 使用方法

修饰器在智能合约中使用非常普遍,常常用于验证输入参数、执行权限检查、记录日志等操作。

比如,在一个智能合约中,某些函数只能由合约部署者使用,而普通用户则没有权限使用。

这里的合约部署者类似于系统管理员,它在系统中具有更大的权力。

下面的例子展示了修饰器如何应用于黑名单功能:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Modifier {
  address owner; // 合约部署者地址
  mapping (address => bool) blacklist; // 账户黑名单

  modifier onlyOwner() {
    require(msg.sender == owner, "Only owner can call this function");
    _; // 执行被修饰的函数
  }

  // 构造函数,保存合约部署者地址
  constructor() {
    owner = msg.sender;
  }

  // 将某地址加入黑名单,只有合约部署者有权调用
  function setBlacklist(address account) onlyOwner external{
    blacklist[account] = true;
  }

  // 查看某地址是否在黑名单中
  function isBlacklist(address account) external view returns (bool) {
    return blacklist[account];
  }
}

onlyOwner 是一个函数修改器,它用来判断调用者是否为合约的部署者,如果是合约的部署者,就继续执行它所修饰的函数,如果不是就回滚交易,并返回错误信息“Only owner can call this function”。

setBlacklist 用于将某地址加入黑名单。这个函数被修饰器 onlyOwner 修饰,所以它只能由合约部署者调用,其它账户是无法调用这个函数的。

isBlacklist 用于查看某地址是否在黑名单中。由于这个函数的声明中没有修饰器,所以它可以被任何人调用。

凡是合约中只能由合约部署者调用的函数,我们都可以在函数声明使用 onlyOwner 修饰,极大简化了权限控制的代码编写。

所以,我们可以将合约中一些通用的操作提取出来,包装为函数修饰器,来提高代码的复用性,改善编码效率。

我们对比一下下面两段代码的区别:

  modifier onlyOwner() {
    require(msg.sender == owner, "Only owner can call this function");
    _; // 继续执行被修饰的函数
  }
  modifier onlyOwner() {
    _; // 先执行被修饰的函数
    require(msg.sender == owner, "Only owner can call this function");
  }

前者是先判断条件,然后再执行被修饰的函数;后者是先执行被修饰的函数,再判断条件。

其中的 _; 表示被修饰函数的执行位置。

3. 带参数的修饰器

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract ModifierWithParam {
  int public counter; 

  modifier isPositive(int x) {
    // 判断 x 是否大于 0,如果大于 0,就继续执行,否则终止执行
    require(x > 0, "x has to be greater than 0"); 
     _; // 执行修饰的函数
  }

   function add(int x) external isPositive(x) {
      counter += x; 
   }
}

修饰器 isPositive 用来判断输入参数是否大于 0,如果大于 0,就继续执行,否则终止执行。这里的修饰器 isPositive 带有一个参数 x,由被修饰的函数传入。

修饰器在智能合约中的使用非常普遍,我们必须熟练掌握。