美文网首页
Solidity语法随笔(一)

Solidity语法随笔(一)

作者: Eric_feng | 来源:发表于2018-09-18 14:17 被阅读30次

    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语法随笔(一)

          本文链接:https://www.haomeiwen.com/subject/oriunftx.html