sodility文档--modifier函数修改器

modifier即函数的修改器,可以用来改变一个函数的行为,控制函数的逻辑。修改器是一种合约属性,可以被继承和重写。
下面以代码为例进行介绍(代码来源于CryptoKitties项目KittyAccessControl.sol合约,详细代码可以查看https://github.com/dapperlabs/cryptokitties-bounty)

modifier onlyCLevel() {
        require(
            msg.sender == cooAddress ||
            msg.sender == ceoAddress ||
            msg.sender == cfoAddress
        );
        _;
    }

前面一段代码是一个修改器,声明了一个约束onlyClevel:仅当当前的地址为ceoAddress或者cfoAddress或者cooAddress时,可以执行后续代码。下划线_是一个占位符,代表了执行函数接下来的代码。
有时你还会看到上面那段代码写成如下形式:

modifier onlyCLevel() {
        if(
            msg.sender != cooAddress &&
            msg.sender != ceoAddress &&
            msg.sender != cfoAddress
        ) throw;
        _;
    }

其实两段代码是等价的,if()throw的写法是较为老式的写法,现在使用require()的写法较多。

function pause() external onlyCLevel whenNotPaused {
        paused = true;
    }

接下来一段代码声明了一个函数pause(),用于暂停合约,这里使用了onlyClevel约束,表明该函数的执行必须要满足onlyClevel条件。
此外函数修改器也支持传入参数,和函数的参数类似,例如:

pragma solidity ^0.4.0;

contract parameter{
    uint balance = 10;

    modifier lowerLimit(uint _balance, uint __withdraw){
        if( _withdraw < 0 || _withdraw > _balance) throw;
        _;
    }

    function f(uint withdraw) lowerLimit(balance, withdraw) returns (uint){
        return balance;
    }
}

在上面这段代码中,修改器lowerLimit传入两个参数,执行修改器的逻辑。函数的执行与否取决于两个参数:_withdraw和_balance。
函数的修改器参数支持表达式,例如:

pragma solidity ^0.4.0;

contract parameterExpression{
    modifier m(uint a){
        if(a > 0)
            _;
    }

    function add(uint a, uint b) private returns(uint){
        return a + b;
    }

    function f() m(add(1, 1)) returns(uint){
        return 1;
    }
}

对于上面的这段代码,修改器m的参数传入了一个表达式:add(a+b),add()表达式在合约中定义了。
Return用在函数中表示返回值,如果函数有返回值标志return,但是由于修改器限制,判断不成功,无法执行函数体内的代码,那么将会返回返回值类型的默认值,例如:

pragma solidity ^0.4.0;

contract Return{
    modifier a(){
        if(false)
            _;
    }

    function uintReturn() A returns(uint){
        uint a = 0;
        return uint(1);
    }

    function stringReturn() A returns(string){
        return "Hello World";
    }
}

对于上面的代码,由于修改器A永远判断不成功,所以uintReturn和stringReturn两个函数的函数体永远无法执行,那么返回值分别是uint和string的默认值:0和空串。
函数修改器允许使用return;来中断当前流程,但是不允许明确的return值,也就是说在修改器中只能存在return;
对于函数修改器,下划线代表函数体,当执行到下划线;这一行的时候,就跳到函数体,执行函数体内的语句,执行完函数体内语句其实还要回到函数修改器,执行下划线_;后面的语句,例如:

pragma solidity ^0.4.0;

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

    modifier A(mapping(bool => uint) mapp){
        if(mapp[true] == 0){
            mapp[true] = 1;
            _;
            mapp[true] = 3;
        }
    }

    function f() A(mapp) returns(uint){
        mapp[true] = 2;
        return mapp[true];
    }
}

对于上面的函数f(),先运行修改器,判断权限,通过权限,则执行修改器判断语句后面的代码:map[true] = 1;,当运行到下划线;这一行的时候,跳到函数体内执行map[true] = 2;,然后retrun map[true]的值。执行完函数体的代码会回到函数修改器下划线;这一行后面的代码,这里还有代码,接着执行map[true] = 3。所以最终map[true]的值为3。
对于一个函数可以有多个修改器限制,在函数定义的时候依次写上,并用加空格分隔,执行的时候也是依次执行。多个修改器是同时限制,也就是说必须满足所有修改器的权限,才可以执行函数体的代码,例如:

pragma solidity ^0.4.0;

contract multiModifier{
    address owner = msg.sender;

    modifier onlyOwner{
        if(msg.sender != owner) throw;
        _;
    }

    modifier inState(bool state){
        if(!state) throw;
        _;
    }

    function f(bool state) onlyOwner inState(state) returns(uint){
        return 1;
    }
}

上面这段代码中两个修改器onlyOwner和inState同时作用于函数f(),只有当两个修改器的权限同时满足的时候,才会执行函数体内的代码,retrun 1。
我们知道合约是可以继承的,在子合约中我们还可以对父合约中的修改器进行重写覆盖,例如:

pragma solidity ^0.4.0;

contract bank{
    modifier transferLimit(uint _withdraw){
        if(_withdraw > 100) throw;
        _;
    }
}

contract ModifierOverride is bank{
    modifier transferLimit(uint _withdraw){
        if(_withdraw > 10) throw;
        _;
    }

    function f(uint withdraw) transferLimit(withdraw) returns(uint){
        return withdraw;
    }
}

上面这段代码中,子合约ModifierOverride继承了父合约bank,那么同样有父合约中的transferLimit修改器,之后在子合约中再次定义transferLimit修改器,就重写了该修改器并覆盖了原修改器,在子合约中transferLimit的限制条件由子合约中重写的条件决定。

你可能感兴趣的:(solidity,modifier,修改器)