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);
}
}
上溢出和下溢出是因为结果数值不在类型的定义范围.
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位.
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作为他们的第一个返回参数,而不是冒泡抛出异常.
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()函数依然执行