solidity中error,panic,require,revert,assert之间的关系.

constant 和 immuable修饰状态变量的区别: 

constant在编译期间已经确定,不能修改。 immutable 可以再合约构造函数中赋值.

Functions can be declared pure in which case they promise not to read from or modify the state.

如果不从状态数据库里读和写数据, 函数可以被声明为pure.   读,写, 不读不写都是针对的状态数据库而言的。

创建合约的时候,给合约地址加盐进行二次处理.

contract C {
    function createDSalted(bytes32 salt, uint arg) public {
        // This complicated expression just tells you how the address
        // can be pre-computed. It is just there for illustration.
        // You actually only need ``new D{salt: salt}(arg)``.
        address predictedAddress = address(uint160(uint(keccak256(abi.encodePacked(
            bytes1(0xff),
            address(this),
            salt,
            keccak256(abi.encodePacked(
                type(D).creationCode,
                abi.encode(arg)
            ))
        )))));

        D d = new D{salt: salt}(arg);
        require(address(d) == predictedAddress);
    }
}

Checked or Unchecked Arithmetic

上溢出和下溢出是因为结果数值不在类型的定义范围.

0.8.0之前数字溢出需要添加checked表达式去做校验, 0.8.0之后,所有的数学算法都会做检查,在溢出的情况下,都会revert.

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
contract C {
    function f(uint a, uint b) pure public returns (uint) {
        // This subtraction will wrap on underflow.
        unchecked { return a - b; }
    }
    function g(uint a, uint b) pure public returns (uint) {
        // This subtraction will revert on underflow.
        return a - b;
    }
}

The call to f(2, 3) will return 2**256-1, 不会报错, while g(2, 3) will cause a failing assertion. 报错.

To avoid ambiguity, you cannot use _; inside an unchecked block.

为了避免歧义,不能使用_;在unchecked的块内。

The following operators will cause a failing assertion on overflow or underflow and will wrap without an error if used inside an unchecked block:

以下操作在溢出的时候回抛出失败的断定assertion,   如果操作在unchecked的块内,会被包裹,没有错误抛出。

++--+, binary -, unary -*/%**

+=-=*=/=%=

Bitwise operators do not perform overflow or underflow checks.  位移动操作不会执行溢出检查, 因为溢出的时候,不会抛出错误.

For example type(uint256).max << 3 does not revert even though type(uint256).max * 8 would.  

type(uint256).max << 3 溢出后,不会抛出异常,并且恢复。type(uint256).max * 8 溢出后,会抛出异常,并且revert.

The second statement in int x = type(int).min; -x; will result in an overflow because the negative range can hold one more value than the positive range.     -x 将会导致溢出, 因为负数的范围比正数范围多持有一个数字.

在所有被int类型占用的比特位中,左起第一个位(即最高位)就是符号位。int类型的符号位上,0表示正数,1表示负数。在32位操作系统下,其余后面31位是数值位。 本来正数和负数位数都是16位, 正数位有一个是符号位,所以正数位是15位, 负数位是16位.

Error handling: Assert, Require, Revert and Exceptions

Solidity uses state-reverting exceptions to handle errors. Such an exception undoes all changes made to the state in the current call (and all its sub-calls) and flags an error to the caller. solidity 使用状态恢复异常处理错误. 这个异常会撤销所有的关于当前调用和子调用的改变,给调用这标注出错误。

当在子调用中发生异常,他们自动冒泡, 除非你用try/catch 捕获异常。 这个规则的例外是send,call,delegatecall,staticcall, 他们返回fase作为他们的第一个返回参数,而不是冒泡抛出异常.

Panic via assert and Error via require

assert 和 require用于检查给予的条件,当不满足的时候,抛出异常。

assert 函数会创建一个panic的错误异常. 是内部异常,代码bug,是需要即可需要修复的异常检查。(比如数字溢出,数组越界,0作为分子,被除等 )

require 创建一个Error的异常.  是业务错误. (没有满足特定的业务条件)

Error is used for “regular” error conditions while Panic is used for errors that should not be present in bug-free code.

Error是业务正常的异常和错误, 是业务异常。 Panic是代码bug,是思维逻辑的异常,是内部异常,是不应该出现的异常.

The error data will be passed back to the caller and can be caught there. Using revert() causes a revert without any error data while revert("description") will create an Error(string) error.

错误数据会被回传给调用者,并且会在那里进行捕获. revert 引起一个没有错误数据的恢复, 而revert("description") 会创建一个Error(string)错误.

Using a custom error instance will usually be much cheaper than a string description, because you can use the name of the error to describe it, which is encoded in only four bytes. A longer description can be supplied via NatSpec which does not incur any costs.

使用定制的错误实例会常常比字串描述异常便宜,因为你可以用4个字节的错误的名字去描述它。更长的描述不会引起任何成本,因为它可以通过NatSpec提供.

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

contract VendingMachine {
    address owner;
    error Unauthorized();
    function buy(uint amount) public payable {
        if (amount > msg.value / 2 ether)
            revert("Not enough Ether provided.");
        // Alternative way to do it:
        require(
            amount <= msg.value / 2 ether,
            "Not enough Ether provided."
        );
        // Perform the purchase.
    }
    function withdraw() public {
        if (msg.sender != owner)
            revert Unauthorized();

        payable(msg.sender).transfer(address(this).balance);
    }
}

require(condition, f()) the function f is executed even if condition is true.

即使condition为true,则f()函数依然执行

你可能感兴趣的:(区块链)