Solidity函数修改器的基本概念及应用

基本概念

函数修改器可以一定程度上改变函数的行为。可以作为函数执行的先行条件,如果符合函数修改器定义的条件,才可以执行函数体内容。关于函数修改器,可以把理解成if的变相。

函数修改器定义

函数修改器的定义语法如下:

    modifier 修改器名 {
        条件体..
        _;
    }

    function a() 修改器名 {
        函数体..
    }

当要执行a()时,会先去执行修改器,判断条件体,如果符合条件,才会继续执行a();如果不符合条件,a()将不执行。”_;”在这里表示的是a().
通过一个小栗子,直观的感受下:

pragma solidity ^0.4.0;

/**
 * 权限控制
 */
contract Ownable {
  address public owner = msg.sender;

  // @notice 检查必须是合约的所有者
  modifier onlyOwner {
    if (msg.sender != owner) throw;
    _;
  }

  // @notice 改变合约的拥有者身份
  // @param _newOwner 新所有者的地址
  function changeOwner(address _newOwner) onlyOwner {
    if(_newOwner == 0x0) throw;
    owner = _newOwner;
  }
}

在上述的例子中,我们实现了只有合约所有者才能修改合约归属的权限的功能。

函数修改器参数

函数修改器可以接收上下文中存在的任意变量组成的表达式,直接在函数修改器中传入参数。

    modifier 修改器名(uint 参数1, string 参数2) {
        if(参数1>10 && 参数2 != "男")
        //条件体..
        _;
    }

函数修改器执行规则

当函数的修改器条件判断不成功,如果函数没有返回值,对应的函数将不执行;如果函数有返回值,那将返回对应类型的默认值。
而函数修改器中的条件体,不论函数是否符合条件,都会继续执行完毕修改器中的后续逻辑。
参考如下实例:

pragma solidity ^0.4.0;

contract Test{
  mapping(bool => uint) public mapp;

  modifier A(mapping(bool => uint) mapp) {
    if(mapp[true] == 0) {
      mapp[true]= 1;
      _;
      mapp[true]= 3;//这句将会最后执行,可以在调试器中查看mapp的值为3。
    }
  }

  function f1() A(mapp) returns(uint) {
    mapp[true] = 2;
    return mapp[true];//函数结束时,mapp值为2.
  }

  modifier B(mapping(bool => uint) mapp) {
    if(mapp[true] == 1) { //条件体判断不成功,导致函数f2讲不会执行。
      mapp[true]= 1;
      _;
      mapp[true]= 3;
    }
    mapp[true]=7;//秉着一站到底的原则,这句将会被最后执行,mapp值为7。
  }

  function f2() B(mapp) returns(uint) {
      mapp[true] = 2;
    return mapp[true];//有返回值的函数,将返回对应类型的默认值,即为0.
  }
}

这里写图片描述

多函数修改器

当一个函数拥有多个函数修改器时,执行顺序是按照先后顺序依次执行。如果有一个不满足,函数即不能执行。

pragma solidity ^0.4.0;

contract Test{


  modifier A(uint a) {
    if(a<10) throw;
    _;
  }

  modifier B(uint b) {
    if(b<10) throw;
    _;
  }

  //必须同时满足A、B,才能执行f()
  function f(uint a, uint b) A(a) B(b) returns(uint) {
      return 777;
  }
}

这里写图片描述

函数修改器的继承与重写

子类可以使用父类中的函数修改器,也可以重写父类的函数修改器。

pragma solidity ^0.4.0;

contract Father{
  modifier A(uint a) {
    if(a > 100) throw;
    _;
  }
}

contract Son is Father{
  //重写父类中的函数修改器
  modifier A(uint a) {
    if(a > 50) throw;
    _;
  }

  function f(uint a) A(a) returns(uint) {
    return 777;
  }
}

应用

结合现实场景中的应用。在一些敏感操作中,我们需要设定特定的权限才允许执行相关操作;再者我们可以利用函数修改器进行数据的校验;还可以利用简单的函数修改器来进行重入锁的机制。

权限控制

pragma solidity ^0.4.0;

contract Ownable {
  address public owner = msg.sender;

  /// @notice 检查必须是合约的所有者
  modifier onlyOwner {
    if (msg.sender != owner) throw;
    _;
  }

  /// @notice 改变合约的拥有者身份
  /// @param _newOwner 新所有者的地址
  function changeOwner(address _newOwner)
  onlyOwner
  {
    if(_newOwner == 0x0) throw;
    owner = _newOwner;
  }
}

数据校验

contract DataVerifiable {

  /// @notice throws if ether was sent accidentally
  modifier refundEtherSentByAccident() {
    if(msg.value > 0) throw;
    _;
  }

  /// @notice throw if an address is invalid
  /// @param _target the address to check
  modifier throwIfAddressIsInvalid(address _target) {
    if(_target == 0x0) throw;
    _;
  }

  /// @notice throw if the id is invalid
  /// @param _id the ID to validate
  modifier throwIfIsEmptyString(string _id) {
    if(bytes(_id).length == 0) throw;
    _;
  }

  /// @notice throw if the uint is equal to zero
  /// @param _id the ID to validate
  modifier throwIfEqualToZero(uint _id) {
    if(_id == 0) throw;
    _;
  }

  /// @notice throw if the id is invalid
  /// @param _id the ID to validate
  modifier throwIfIsEmptyBytes32(bytes32 _id) {
    if(_id == "") throw;
    _;
  }
}

重入锁实现

pragma solidity ^0.4.0;

contract Mutex {
    bool locked;
    modifier noReentrancy() {
        require(!locked);
        locked = true;
        _;
        locked = false;
    }

    // 这个函数使用了noReentrancy修改器,这保证了在f函数内部无法再次使用调用f函数
    // 在执行return 7时也执行了函数修改器中的locked = false
    function f() noReentrancy returns (uint) {
        require(msg.sender.call());
        return 7;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_33764491/article/details/80409877