乐知付加密服务平台

如果你有资源, 平台可以帮你实现内容变现, 无需搭建知识付费服务平台。

点击访问官方网站 https://lezhifu.cc

扫码关注公众号 乐知付加密服务平台-微信公众号
Solidity中函数修改器modifier详解 | chenzuoli's blog

Solidity中函数修改器modifier详解

      modifier即函数的修改器,可以用来改变一个函数的行为,控制函数的逻辑。修改器是一种合约属性,可以被继承和重写。

1.函数修改器

      下面以代码为例进行介绍(代码来源于CryptoKitties项目KittyAccessControl.sol合约,详细代码可以查看https://github.com/dapperlabs/cryptokitties-bounty)

1
2
3
4
5
6
7
8
modifier onlyCLevel() {
require(
msg.sender == cooAddress ||
msg.sender == ceoAddress ||
msg.sender == cfoAddress
);
_;
}

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

1
2
3
4
5
6
7
8
modifier onlyCLevel() {
if(
msg.sender != cooAddress &&
msg.sender != ceoAddress &&
msg.sender != cfoAddress
) throw;
_;
}

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

1
2
3
function pause() external onlyClevel whenNotPaused {
paused = true;
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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;
}
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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;
}
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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";
}
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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];
}
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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;
}
}

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;上面这段代码中两个修改器onlyOwnerinState同时作用于函数f(),只有当两个修改器的权限同时满足的时候,才会执行函数体内的代码,retrun 1

2.重写修改器

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;我们知道合约是可以继承的,在子合约中我们还可以对父合约中的修改器进行重写覆盖,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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;
}
}

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


Never regret a day in your life, good days give you happiness, bad days give you experiences.

书山有路勤为径,学海无涯苦作舟。

欢迎关注微信公众号:【程序员写书】
程序员写书

喜欢宠物的朋友可以关注:【电巴克宠物Pets】
电巴克宠物

一起学习,一起进步。

-------------本文结束感谢您的阅读-------------