Solidity语法随笔(一)

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() 用于预防不应该发生的情况,但不应该使条件错误。

另外,“除非认为之前的检查(用 ifrequire )会导致无法验证 overflow,否则不应该盲目使用 assert 来检查 overflow

你可能感兴趣的:(Solidity语法随笔(一))