我正在通过查看文档来寻找有关require和assert以及throw和revert之间的区别。

assert(bool条件):如果条件为false,则中止执行并恢复状态更改(用于内部错误)

require(bool条件):如果条件为false,则中止执行并恢复状态更改(用于格式错误的输入)

特别是关于assert和require,如何划分格式错误的输入和内部错误之间的界限?

原文地址

3 人回答 0

3 个回答
投票数
最旧发布
最近发布

回答发布于 2018-09-11 21:27:54

assert()require()之间进行选择时需要考虑两个方面

  1. gas效率
  2. 字节码分析

gas效率

assert(false)编译为0xfe,这是一个无效的操作码,耗尽所有剩余的gas,并恢复所有的变化。

require(false)编译为0xfd,这是REVERT操作码,意味着它将退还剩余的gas。操作码也可以返回一个值(对于调试很有用),但我不认为现在Solidity支持这个值。(2017年11月21日)

字节码分析

来自文档(强调我的)

> require函数应该用于保证满足有效条件,如输入或合约状态变量是否满足条件,或验证调用外部合约得到的返回值。如果使用得当,分析工具可以评估你的合约,来识别会得到失败断言的条件和函数调用。正常运行的代码永远不会得到失败的断言语句; 如果发生这种情况,说明你的合约中有错误,应该修复。

以上摘录是对实际和未记载的SMTChecker的引用(截至2017-11-21)。

我使用一些启发式方法来帮助我决定使用哪个。

使用require()

  • 验证用户输入
  • 验证外部合约的响应
  • 即,使用require(external.send(amount))
  • 在执行状态更改操作之前验证状态条件,例如在一个owned合约情况下
  • 通常,你应该更频繁地使用require
  • 通常,它应该用于函数的开头

 使用assert()

  • 检查溢出/下溢
  • 检查不变量
  • 进行更改后验证合约状态
  • 避免永远不可能的条件
  • 通常,你应该更少使用assert
  • 通常,它应该在你的函数结束时使用

基本上,assert就是为了防止发生一些非常糟糕的事情,但是条件不应该有可能被验证为假的。

历史记录:

require()assert()函数在v0.4.10版本,Byzantium分支之前被添加到Solidity中。 在Byzantium之前,他们的行为相同,但已经编译成不同的操作码。这意味着在Byzantium之前部署的一些合约在分支后表现不同,主要区别在于退还未使用的gas。

||
||

回答发布于 2018-09-11 21:27:53

我用require进行输入验证,因为它比if/throw更有效一点。

function foo(uint amount) {
    require(amount < totalAmount);
    ...
}

assert应该更多地用于运行时的错误捕获:

function foo(uint amount) {
    ...
    __check = myAmount;
        myAmount -= amount;
    assert(myAmount < __check);
    ...
}

在以后版本的以太坊(Ethereum)中,revert将还原更改并退还未使用的gas,但ATM的行为方式还是与抛出相同。

||
||

回答发布于 2018-09-11 21:27:53

我觉得没有一个答案是正确的。

assert是为条件而保留的,因为可以预见静态代码分析工具(可能是未来版本中的Solidity编译器)将能够在编译时检测错误来警告开发人员。

require用于不正确的输入数据产生的错误条件(与预期/有效输入数据相比),直到执行时才能检测到。这对应于编程语言argot中的函数前提条件。由于输入数据的无限可能性,编译器无法提供帮助。

throw被弃用以支持revert。

revert用于影响业务逻辑的错误条件。例如,当投票已经结束时,有人会发送投票。

requirerevert与内部EVM实现大致相似,但开发人员欣赏这种区别。

||
||

回答发布于 2018-09-11 21:27:53

我用require进行输入验证,因为它比if/throw更有效一点。

function foo(uint amount) {
    require(amount < totalAmount);
    ...
}

assert应该更多地用于运行时的错误捕获:

function foo(uint amount) {
    ...
    __check = myAmount;
        myAmount -= amount;
    assert(myAmount < __check);
    ...
}

在以后版本的以太坊(Ethereum)中,revert将还原更改并退还未使用的gas,但ATM的行为方式还是与抛出相同。

||
||

回答发布于 2018-09-11 21:27:53

我觉得没有一个答案是正确的。

assert是为条件而保留的,因为可以预见静态代码分析工具(可能是未来版本中的Solidity编译器)将能够在编译时检测错误来警告开发人员。

require用于不正确的输入数据产生的错误条件(与预期/有效输入数据相比),直到执行时才能检测到。这对应于编程语言argot中的函数前提条件。由于输入数据的无限可能性,编译器无法提供帮助。

throw被弃用以支持revert。

revert用于影响业务逻辑的错误条件。例如,当投票已经结束时,有人会发送投票。

requirerevert与内部EVM实现大致相似,但开发人员欣赏这种区别。

||
||

回答发布于 2018-09-11 21:27:54

assert()require()之间进行选择时需要考虑两个方面

  1. gas效率
  2. 字节码分析

gas效率

assert(false)编译为0xfe,这是一个无效的操作码,耗尽所有剩余的gas,并恢复所有的变化。

require(false)编译为0xfd,这是REVERT操作码,意味着它将退还剩余的gas。操作码也可以返回一个值(对于调试很有用),但我不认为现在Solidity支持这个值。(2017年11月21日)

字节码分析

来自文档(强调我的)

> require函数应该用于保证满足有效条件,如输入或合约状态变量是否满足条件,或验证调用外部合约得到的返回值。如果使用得当,分析工具可以评估你的合约,来识别会得到失败断言的条件和函数调用。正常运行的代码永远不会得到失败的断言语句; 如果发生这种情况,说明你的合约中有错误,应该修复。

以上摘录是对实际和未记载的SMTChecker的引用(截至2017-11-21)。

我使用一些启发式方法来帮助我决定使用哪个。

使用require()

  • 验证用户输入
  • 验证外部合约的响应
  • 即,使用require(external.send(amount))
  • 在执行状态更改操作之前验证状态条件,例如在一个owned合约情况下
  • 通常,你应该更频繁地使用require
  • 通常,它应该用于函数的开头

 使用assert()

  • 检查溢出/下溢
  • 检查不变量
  • 进行更改后验证合约状态
  • 避免永远不可能的条件
  • 通常,你应该更少使用assert
  • 通常,它应该在你的函数结束时使用

基本上,assert就是为了防止发生一些非常糟糕的事情,但是条件不应该有可能被验证为假的。

历史记录:

require()assert()函数在v0.4.10版本,Byzantium分支之前被添加到Solidity中。 在Byzantium之前,他们的行为相同,但已经编译成不同的操作码。这意味着在Byzantium之前部署的一些合约在分支后表现不同,主要区别在于退还未使用的gas。

||
||

回答发布于 2018-09-11 21:27:54

assert()require()之间进行选择时需要考虑两个方面

  1. gas效率
  2. 字节码分析

gas效率

assert(false)编译为0xfe,这是一个无效的操作码,耗尽所有剩余的gas,并恢复所有的变化。

require(false)编译为0xfd,这是REVERT操作码,意味着它将退还剩余的gas。操作码也可以返回一个值(对于调试很有用),但我不认为现在Solidity支持这个值。(2017年11月21日)

字节码分析

来自文档(强调我的)

> require函数应该用于保证满足有效条件,如输入或合约状态变量是否满足条件,或验证调用外部合约得到的返回值。如果使用得当,分析工具可以评估你的合约,来识别会得到失败断言的条件和函数调用。正常运行的代码永远不会得到失败的断言语句; 如果发生这种情况,说明你的合约中有错误,应该修复。

以上摘录是对实际和未记载的SMTChecker的引用(截至2017-11-21)。

我使用一些启发式方法来帮助我决定使用哪个。

使用require()

  • 验证用户输入
  • 验证外部合约的响应
  • 即,使用require(external.send(amount))
  • 在执行状态更改操作之前验证状态条件,例如在一个owned合约情况下
  • 通常,你应该更频繁地使用require
  • 通常,它应该用于函数的开头

 使用assert()

  • 检查溢出/下溢
  • 检查不变量
  • 进行更改后验证合约状态
  • 避免永远不可能的条件
  • 通常,你应该更少使用assert
  • 通常,它应该在你的函数结束时使用

基本上,assert就是为了防止发生一些非常糟糕的事情,但是条件不应该有可能被验证为假的。

历史记录:

require()assert()函数在v0.4.10版本,Byzantium分支之前被添加到Solidity中。 在Byzantium之前,他们的行为相同,但已经编译成不同的操作码。这意味着在Byzantium之前部署的一些合约在分支后表现不同,主要区别在于退还未使用的gas。

||
||

回答发布于 2018-09-11 21:27:53

我用require进行输入验证,因为它比if/throw更有效一点。

function foo(uint amount) {
    require(amount < totalAmount);
    ...
}

assert应该更多地用于运行时的错误捕获:

function foo(uint amount) {
    ...
    __check = myAmount;
        myAmount -= amount;
    assert(myAmount < __check);
    ...
}

在以后版本的以太坊(Ethereum)中,revert将还原更改并退还未使用的gas,但ATM的行为方式还是与抛出相同。

||
||

回答发布于 2018-09-11 21:27:53

我觉得没有一个答案是正确的。

assert是为条件而保留的,因为可以预见静态代码分析工具(可能是未来版本中的Solidity编译器)将能够在编译时检测错误来警告开发人员。

require用于不正确的输入数据产生的错误条件(与预期/有效输入数据相比),直到执行时才能检测到。这对应于编程语言argot中的函数前提条件。由于输入数据的无限可能性,编译器无法提供帮助。

throw被弃用以支持revert。

revert用于影响业务逻辑的错误条件。例如,当投票已经结束时,有人会发送投票。

requirerevert与内部EVM实现大致相似,但开发人员欣赏这种区别。

||
||