assert() , require() 和 revert() 函数
Solidity 的错误处理模式
传统方法:采用 throw 和 if ... throw 模式
例:
这行代码:
if(msg.sender != owner) { throw; }
完全等价于如下三种形式:
if(msg.sender != owner) { revert(); }
assert(msg.sender == owner);
require(msg.sender == owner);
注意在 assert() 和 require() 例子中的条件声明,是 if 例子中条件块取反,也就是用 ==代替了 != 。
区别:
assert():想象为一个过于自信的实现方式,即使有错误,也会执行并扣除gas。
require():想象为一个更有礼貌些的实现方式,会发现错误,并且原谅所犯错误(译注:不扣除 gas)。
revert():碰到无效代码后,仍将回滚所有状态,但是会用两种不同于“无效代码”方式处理:允许返回一个数值,
将剩余gas返还调用者。
require()用于:
确认有效条件,例如输入,
确认合约声明变量是一致的
从调用到外部合约返回有效值
如果正确使用,分析工具会评估合约并分辨出引起assert调用错误的条件和函数。正确函数代码将会避免引起调用错误的 assert 声明;如果发生就意味着合约中存在需要修复的bug。
为了更清楚地解释:require() 声明失败应该被认为是正常和健壮的情况(跟 revert() 一样);而当 assert() 声明失败时,则意味着有些东西失控了,需要修复代码中的问题。
判断正确使用场景:
require():
- 验证用户输入,即:
require(input<20); - 验证外部合约响应,即:
require(external.send(amount)); - 执行合约前,验证状态条件,即:
require(block.number > SOME_BLOCK_NUMBER)或者require(balance[msg.sender]>=amount) - 一般地,尽量使用
require函数 - 一般地,
require应该在函数最开始的地方使用
revert():
- 处理与
require()同样的类型,但是需要更复杂处理逻辑的场景
如果有复杂的 if/else 逻辑流,那么应该考虑使用 revert() 函数而不是require()。记住,复杂逻辑意味着更多的代码。
assert():
- 检查 overflow/underflow,即:
c = a+b; assert(c > b) - 检查非变量(invariants),即:
assert(this.balance >= totalSupply); - 验证改变后的状态
- 预防不应该发生的条件
- 一般地,尽量少使用
assert调用 - 一般地,
assert应该在函数结尾处使用
基本上,require() 应该被用于函数中检查条件,assert() 用于预防不应该发生的情况,但不应该使条件错误。
另外,“除非认为之前的检查(用 if 或 require )会导致无法验证 overflow,否则不应该盲目使用 assert 来检查 overflow”









网友评论