Solidity v0.6.0重大更新¶
本节重点介绍Solidity 版本0.6.0 中引入的重大突破性变化,以及更改背后的原因以及如何更新受影响的代码。
有关完整列表,请检查 更新日志.
需要明确指定的更改¶
本节列出了现在需要更明确地显示代码的更改, 但是语义不会改变。 对于大多数情况,编译器将提供建议。
现在,仅当函数被标记为
virtual
或在接口中定义 时,才可以覆盖。
在接口外部没有实现的函数必须标记为 virtual
。
覆盖函数或修饰符时,必须使用新关键字 override
。 覆盖多个基类定义的函数或修饰符时, 需要像这样 override(Base1, Base2)
列出.
访问数组的
length
现在是只读的, 即便是storage 数组. 不能通过修改length来调整数组的大小, 必须通过函数push()
,push(value)
或pop()
或者分配一个完整的数组(不过这会覆盖现有内容)。 这个修改背后的原因是为了防止存储冲突.关键字
abstract
用来标记一个抽象合约. 如果合约有没有实现的函数, 需要使用。抽象合约不能通过new
操作符创建,并且不能在编译期生成字节码(bytecode)。库需要实现所有的函数,不仅仅是内部函数.
内联汇编中声明的变量名称可以不再以
_slot
或_offset
结尾。内联汇编中的变量声明可能不会在内联汇编块之外屏蔽声明。
如果名称包含一个点,则该点之前的前缀可能与内联汇编块外部的任何声明都没有冲突。
现在不允许状态变量屏蔽。 派生合约只能声明基类合约中都没有同名的可见状态变量
x
(即如果基类合约中有共有的 状态变量x
, 则派生合约不能在声明x
)。
语义和句法变化¶
本节列出了必须修改代码的更改.
现在禁止从外部函数类型到
address
的转换。 现在外部函数类型具有一个称为address
的成员属性,类似于现有的selector
成员。对于动态的存储数组, 函数
push(value)
不再返回长度(现在什么都不返回).未命名的函数通常称为
fallback function
,已拆分为一个使用fallback
关键字定义的回退函数 和 使用关键字receive
定义的接受以太函数.如果有
receive
函数, 向合约转账的时候会调用,不管是否是调用数据(即便没有以太接收),receive
函数隐含带有payable
.新的回退函数会被调用,当没有其他的函数被匹配时, (如果不存在
receive
函数,则没有调用数据的转账也会调用回退函数). 回退函数可以标记为payable
(也可以不标记). 如果没有payable
那么附加以太的调用会revert.
如果是需要实现升级或代理模式,则仅需要实现新的回退函数。
新特性¶
本节列出了在Solidity 0.6.0 之前不可能实现的事情,或者在Solidity 0.6.0之前很难实现的事情。
加入了 try/catch 语句 使您可以对失败的外部调用做出反应。
struct
和enum
类型可以在文件级别声明.数组切片可以用于 calldata 数组, 例如:
abi.decode(msg.data[4:], (uint, uint))
是一个对函数调用payload进行解码底层方法。Natspec在开发人员文档中支持多个返回参数,并强制执行与
@param
的同名检查。Yul和Inline Assembly有一个名为
leave
的新语句,该语句退出当前函数.现在可以通过
payable(x)
把address
转换为address payable
, 当然x
需要是 地址类型.
接口变化¶
本节列出了与语言本身无关的更改,但这些更改会影响编译器的接口。 如果命令行上使用编译器的, 或编程方式使用, 或分析编译器输出时, 都会产生改变.
新错误报告器¶
引入了一个新的错误报告器,能够在命令行输出可读性更强的错误信息。默认是开启的,但可以通过添加 --old-reporter
参数使用旧版本的错误报告器。
Metadata 哈希选项¶
编译器现在默认在字节码的末尾自带 IPFS 元数据文件的哈希(更多的细节请参见 contract metadata)。在0.6.0版本之前,编译器默认自带`Swarm <https://ethersphere.github.io/swarm-home/>`_ ,为了继续支持这个特性,引入了新的命令行选项 --metadata-hash
。在命令行选项中,可以选择将 ipfs
或 swarm
传入 --metadata-hash
来进行选择。
如果传入 none
则会不附带任何哈希值。
这些变化可以参见 Standard JSON Interface 并且影响编译器生成的元数据JSON。
推荐阅读元数据的方法是去读最后的两字节,以决定CBOR编码,并且对数据区块选择合适的解码。参见: metadata section。
Yul 优化器¶
与传统的字节码优化器一起, Yul 优化器现在默认开启,当你对编译器使用 --optimize
参数的时候,并且可以通过 --no-optimize-yul
参数关闭。这一选项主要影响的是 ABIEncoderV2。
C API 的变化¶
使用 libsolc
的C API的客户端代码现在由编译器使用的内存控制。 solidity_free
被重命名为 solidity_reset``来保持一致,添加了 ``solidity_alloc
函数和 solidity_free
, solidity_compile
的返回值字符串现在必须通过 solidity_free()
来明确。
怎样修改代码¶
本节提供有关如何为每个重大变更更新先前代码的详细说明。
如果
f
是外部函数类型,address(f)
修改为f.address
接收以太的函数,
function () external [payable] { ... }
修改为receive() external payable { ... }
,fallback() external [payable] { ... }
或者两个度加上. 只要有可能,最好是仅仅使用receive
函数.修改
uint length = array.push(value)
为array.push(value);
. 通过array.length
获取长度.修改
array.length++
为array.push()
去增加storage数组长度, 用pop()
去减少storage数组长度.对于函数的
@dev
开发这文档中的每个命名返回参数,请定义一个@return
条目,其中将返回参数名称作为第一个单词。 例如。 已定义函数f()
是这样function f() public returns (uint value)
, 记录返回值的文档注释是这样:@return value 这是返回值.
您可以混合使用命名和未命名的返回参数,只要按它们在返回元组类型中出现的顺序排列即可。为内联汇编中的变量声明选择与内联汇编块外的声明不冲突的唯一标识符。
为每个非接口函数添加
virtual
. 对于单继承,请在每个重写函数中添加override
。 对于多重继承,添加override(A, B, ..)
, 在在括号中列出所有覆盖函数的的合约。
当多个基类合约有相同定义的函数时,继承合约必须覆盖所有冲突的函数。