solidity错误处理
官方文档:
https://solidity.readthedocs.io/en/develop/control-structures.html#error-handling-assert-require-revert-and-exceptions
require和assert方法的区别:
https://ethereum.stackexchange.com/questions/15166/difference-between-require-and-assert-and-the-difference-between-revert-and-thro
程序示例:
pragma solidity ^0.4.0; contract Sharer { function sendHalf(address addr) public payable returns (uint balance) { require(msg.value % 2 == 0); // Only allow even numbers uint balanceBeforeTransfer = this.balance; addr.transfer(msg.value / 2); // Since transfer throws an exception on failure and // cannot call back here, there should be no way for us to // still have half of the money. assert(this.balance == balanceBeforeTransfer - msg.value / 2); return this.balance; } }
require和assert适用范围:
An assert
-style exception is generated in the following situations:
- If you access an array at a too large or negative index (i.e.
x[i]
wherei >= x.length
ori < 0
). - If you access a fixed-length
bytesN
at a too large or negative index. - If you divide or modulo by zero (e.g.
5 / 0
or23 % 0
). - If you shift by a negative amount.
- If you convert a value too big or negative into an enum type.
- If you call a zero-initialized variable of internal function type.
- If you call
assert
with an argument that evaluates to false.
A require
-style exception is generated in the following situations:
- Calling
throw
. - Calling
require
with an argument that evaluates tofalse
. - If you call a function via a message call but it does not finish properly (i.e. it runs out of gas, has no matching function, or throws an exception itself), except when a low level operation
call
,send
,delegatecall
orcallcode
is used. The low level operations never throw exceptions but indicate failures by returningfalse
. - If you create a contract using the
new
keyword but the contract creation does not finish properly (see above for the definition of “not finish properly”). - If you perform an external function call targeting a contract that contains no code.
- If your contract receives Ether via a public function without
payable
modifier (including the constructor and the fallback function). - If your contract receives Ether via a public getter function.
- If a
.transfer()
fails.
Internally, Solidity performs a revert operation (instruction 0xfd
) for a require
-style exception and executes an invalid operation (instruction 0xfe
) to throw an assert
-style exception. In both cases, this causes the EVM to revert all changes made to the state. The reason for reverting is that there is no safe way to continue execution, because an expected effect did not occur. Because we want to retain the atomicity of transactions, the safest thing to do is to revert all changes and make the whole transaction (or at least call) without effect. Note that assert
-style exceptions consume all gas available to the call, while require
-style exceptions will not consume any gas starting from the Metropolis release.
总得来说,两者都会使EVM回滚交易,不会造成任何变更。require适用于做输入检查,assert用来检查运行时内部错误(比如数组下标越界和除零错误)。require在Solidity Metropolis版本后将不消耗gas,而assert会消耗完所有的gas(gaslimit)。
https://medium.com/taipei-ethereum-meetup/%E6%AF%94%E8%BC%83-require-assert-%E5%92%8C-revert-%E5%8F%8A%E5%85%B6%E9%81%8B%E4%BD%9C%E6%96%B9%E5%BC%8F-30c24d534ce4