坚固性v0.8.0突破性变化
本节重点介绍Solidity版本0.8.0中引入的主要突破性更改。有关完整列表,请查看 the release changelog 。
无声的语义变化
本节列出现有代码在没有编译器通知的情况下更改其行为的更改。
- 下溢和上溢时恢复算术运算。您可以使用 - unchecked {{ ... }}若要使用先前的包装行为,请执行以下操作。- 检查溢出是非常常见的,所以我们将其设为默认值以提高代码的可读性,即使这会略微增加汽油成本。 
- 默认情况下,ABI编码器v2处于激活状态。 - 您可以使用以下命令选择使用旧行为 - pragma abicoder v1;。语料库- pragma experimental ABIEncoderV2;仍然有效,但已弃用并且没有任何效果。如果您想明确表示,请使用- pragma abicoder v2;取而代之的是。- 请注意,ABI编码器v2比v1支持更多的类型,并对输入执行更多的健全性检查。当ABI编码器v2包含不符合参数类型的数据时,ABI编码器v2会使一些函数调用变得更昂贵,并且它还可以使未使用ABI编码器v1还原的协定调用还原。 
- 幂运算是右结合的,即表达式 - a**b**c被解析为- a**(b**c)。在0.8.0之前,它被解析为- (a**b)**c。- 这是解析求幂运算符的常用方法。 
- 失败的断言和其他内部检查(如被零除或算术溢出)不会使用无效操作码,而是使用REVERT操作码。更具体地说,它们将使用等于函数调用的错误数据 - Panic(uint256)具有特定于环境的错误代码。- 这将节省错误方面的成本,同时仍然允许静电分析工具将这些情况与无效输入(如失败)的恢复区分开来 - require。
- 如果访问存储中长度编码不正确的字节数组,则会导致死机。除非使用内联程序集修改存储字节数组的原始表示形式,否则协定无法进入这种情况。 
- 如果在数组长度表达式中使用常量,则以前版本的实心度将在求值树的所有分支中使用任意精度。现在,如果将常量变量用作中间表达式,则它们的值将以与在运行时表达式中使用时相同的方式正确舍入。 
- 类型 - byte已被移除。那是一个别名- bytes1。
新的限制
本节列出可能导致现有合同不再编译的更改。
- 对文字的显式转换有新的限制。在以下情况下,以前的行为可能是模棱两可的: - 从负文字和大于以下的文字进行显式转换 - type(uint160).max至- address是不允许的。
- 文字和整数类型之间的显式转换 - T仅当文本位于- type(T).min和- type(T).max。具体地说,要替换的用法是- uint(-1)使用- type(uint).max。
- 只有当文字可以表示枚举中的值时,才允许在文字和枚举之间进行显式转换。 
- 文字和文本之间的显式转换 - address类型(例如- address(literal))有这样的类型- address而不是- address payable。人们可以通过使用显式转换来获得付费地址类型,即,- payable(literal)。
 
- Address literals 有这样的类型 - address而不是- address payable。它们可以转换为- address payable通过使用显式转换,例如- payable(0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF)。
- 对显式类型转换有新的限制。仅当符号、宽度或类型类别最多更改一次时才允许转换 ( - int,- address,- bytesNN等)。要执行多个更改,请使用多个转换。- 让我们使用记号 - T(S)表示显式转换- T(x),在哪里,- T和- S是类型,并且- x是类型为的任意变量- S。这种不允许的转换的一个例子是- uint16(int8)因为它将宽度(8位更改为16位)和符号(有符号整数更改为无符号整数)。为了进行转换,必须经过中间类型。在上一个示例中,这将是- uint16(uint8(int8))或- uint16(int16(int8))。请注意,这两种转换方式将产生不同的结果,例如,对于- -1。以下是此规则不允许的一些转换示例。- address(uint)和- uint(address):同时转换文字类别和宽度。将此替换为- address(uint160(uint))和- uint(uint160(address))分别为。
- payable(uint160),- payable(bytes20)和- payable(integer-literal):同时转换类型类别和状态可变。将此替换为- payable(address(uint160)),- payable(address(bytes20))和- payable(address(integer-literal))分别为。请注意,- payable(0)是有效的,并且是规则的例外。
- int80(bytes10)和- bytes10(int80):同时转换TYPE-CATEGORY和SIGN。将此替换为- int80(uint80(bytes10))和- bytes10(uint80(int80)分别为。
- Contract(uint):同时转换文字类别和宽度。将此替换为- Contract(address(uint160(uint)))。
 - 这些转换是不允许的,以避免模棱两可。例如,在表达式中 - uint16 x = uint16(int8(-1)),的价值- x将取决于首先应用符号还是宽度转换。
- 函数调用选项只能提供一次,即 - c.f{{gas: 10000}}{{value: 1}}()无效,必须更改为- c.f{{gas: 10000, value: 1}}()。
- 全局函数 - log0,- log1,- log2,- log3和- log4已经被移走了。- 这些是在很大程度上未使用的低级函数。它们的行为可以从内联程序集访问。 
- enum定义包含的成员不能超过256个。- 这将使您可以安全地假设ABI中的基础类型始终是 - uint8。
- 名称为 - this,- super和- _是不允许的,公共函数和事件除外。例外情况是,可以声明使用不允许使用此类函数名称的语言实现的约定的接口。
- 删除对 - \b,- \f,以及- \v代码中的转义序列。它们仍然可以通过十六进制转义插入,例如- \x08,- \x0c,以及- \x0b,分别为。
- 全局变量 - tx.origin和- msg.sender有这样的类型- address而不是- address payable。你可以把它们转换成- address payable通过使用显式转换,即,- payable(tx.origin)或- payable(msg.sender)。- 之所以进行此更改,是因为编译器无法确定这些地址是否可支付,因此现在需要显式转换才能使此要求可见。 
- 显式转换为 - address类型始终返回不可支付的- address键入。特别是,以下显式转换的类型- address而不是- address payable:- address(u)哪里- u是类型为- uint160。一个人可以转换成- u输入到文字中- address payable通过使用两个显式转换,即,- payable(address(u))。
- address(b)哪里- b是类型为- bytes20。一个人可以转换成- b输入到文字中- address payable通过使用两个显式转换,即,- payable(address(b))。
- address(c)哪里- c是一份合同。以前,此转换的返回类型取决于合约是否可以接收以太(通过具有接收功能或支付回退功能)。转换- payable(c)具有这样的类型- address payable并且只有当合同- c可以接受以太。一般说来,人们总是可以转换成- c输入到文字中- address payable通过使用以下显式转换:- payable(address(c))。请注意,- address(this)属于与…相同的类别- address(c)同样的规则也适用于它。
 
- 这个 - chainid现在考虑内联程序集中的内置- view而不是- pure。
- 一元求反不能再用于无符号整数,只能用于有符号整数。 
界面更改
- 的输出 - --combined-json已更改:JSON字段- abi,- devdoc,- userdoc和- storage-layout现在是子对象。在0.8.0之前,它们通常被序列化为字符串。
- “遗留AST”已被移除 ( - --ast-json在命令行界面上,- legacyAST用于标准JSON)。使用“紧凑AST” (- --ast-compact--json响应。- AST)作为替代。
- 老错误记者 ( - --old-reporter)已删除。
如何更新您的代码
- 如果您依赖于换行算法,请将每个运算用 - unchecked {{ ... }}。
- 可选:如果使用SafeMath或类似的库,请更改 - x.add(y)至- x + y,- x.mul(y)至- x * y等。
- 添加 - pragma abicoder v1;如果您想继续使用旧的ABI编码器。
- 可以选择删除 - pragma experimental ABIEncoderV2或- pragma abicoder v2因为它是多余的。
- 改变 - byte至- bytes1。
- 如果需要,添加中间显式类型转换。 
- 联合收割机 - c.f{{gas: 10000}}{{value: 1}}()至- c.f{{gas: 10000, value: 1}}()。
- 改变 - msg.sender.transfer(x)至- payable(msg.sender).transfer(x)或使用存储的变量- address payable键入。
- 改变 - x**y**z至- (x**y)**z。
- 使用内联程序集替代 - log0,.,- log4。
- 通过从类型的最大值中减去无符号整数并加1(例如 - type(uint256).max - x + 1,同时确保 x 不是零)