Solidity 0.6 带来的一些重大变化

这又是 Solidity 一个较大版本的升级,带来了一些对老版本不兼容的一些变化。

## 0x01 新的 fallback 函数写法 在 0.6 之前的版本,我们可以定义下面的 fallback 函数,用来通过合约接收 eth 转账或未指定明确合约函数的调用。 ``` function() external payable { currentBalance = address(this).balance + msg.value; } ``` 从 0.6 开始,这种写法就要报编译错误了。 ![](https://img.learnblockchain.cn/2020/01/15790547315852.jpg) 新的写法是下面这样的: ``` fallback() external { } receive() payable external { currentBalance = currentBalance + msg.value; } ``` 对于这种新的写法,有几点是要注意的: 1. fallback 和 receive 不是普通函数,而是新的函数类型,有特别的含义,所以在它们前面加 function 这个关键字。加上 function 之后,它们就变成了一般的函数,只能按一般函数来去调用。 2. 每个合约最多有一个不带任何参数不带 function 关键字的 fallback 和 receive 函数。 3. receive 函数类型必须是 payable 的,并且里面的语句只有在通过外部地址往合约里转账的时候执行。 fallback 函数类型可以是 payable 也可以不是 payable 的,如果不是 payable 的,可以往合约发送非转账交易,如果交易里带有转账信息,交易会被 revert;如果是 payable 的,自然也就可以接受转账了。 4. 尽管 fallback 可以是 payable 的,但并不建议这么做,声明为 payable 之后,其所消耗的 gas 最大量就会被限定在 2300。 ## 0x02 对合约继承更好的支持 这个版本之前合约继承可以这么写的,看起来比较简单,语义上并不是很清晰。 ``` contract Employee { function getSalary() public; } contract Manager is Employee { function increaseSalary() public { } function getSalary() public { } } ``` 从 0.6 开始,solidity 引入了 abstract, virtual, override 几个关键字,继承关系需要用下面的写法。 ``` abstract contract Employee { function getSalary() public virtual; } contract Manager is Employee { function increaseSalary() public { } function getSalary() public override { } } ``` ## 0x03 对 try...catch 机制的支持 在之前的 solidity 版本,我们在当前合约发起对外部合约调用的话,如果外部合约调用执行失败被 revert,外部合约状态会被回滚,当前合约状态也会被回滚。但有时候我们并不想这样,要是能够捕获外部合约调用异常,然后根据情况做自己的处理不是更好么? ``` // 这是我们需要调用的外部合约接口 interface DataFeed { function getData(address token) external returns (uint value); } contract FeedConsumer { DataFeed feed; uint errorCount; function rate(address token) public returns (uint value, bool success) { // 如果外部合约调用错误次数超过 10 次,就不再进行更多调用了 require(errorCount < 10); try feed.getData(token) returns (uint v) { return (v, true); } catch Error(string memory /* 出错原因 */) { // 这块儿代码只有在对 DataFeed 调用失败时才会执行,通常是不满足外部合约 require 语句条件或触发 revert 语句时所引起的调用失败 errorCount++; return (0, false); } catch (bytes memory) { // 当外部调用触发 assert 语句或除 0 等比较严重错误时会执行这个 catch 块 errorCount++; return (0, false); } } } ``` ## 0x04 其它 上面只是列了几个比较大的变化,还有一些其它变化也是值得注意的: 1. 动态数组的长度从 0.6 开始不可更改了。 2. 开始部分支持数组切片了。 3. 结构体和枚举类型可以在合约外声明了,之前是只能在合约内声明的。 4. 如果父合约声明了某个非 private 的状态变量,子合约中就不能再声明同名状态变量。 5. 从 address 到 address payable 的转换现在可以通过 payable(x) 进行 ,其中 x 必须是 address 类型。 ##参考资料 【1】https://solidity.readthedocs.io/en/latest/060-breaking-changes.html 【2】https://medium.com/coinmonks/solidity-v0-6-0-is-here-things-you-should-know-7d4ab5bca5f1 【3】https://vomtom.at/solidity-0-6-0-breaking-changes-hands-on-walkthrough/ *作者:Ashton* *原文链接:https://www.jianshu.com/p/d52c31b14b27*

0x01 新的 fallback 函数写法

在 0.6 之前的版本,我们可以定义下面的 fallback 函数,用来通过合约接收 eth 转账或未指定明确合约函数的调用。

function() external payable {
    currentBalance = address(this).balance + msg.value;
}

从 0.6 开始,这种写法就要报编译错误了。

Solidity 0.6 带来的一些重大变化插图

新的写法是下面这样的:

fallback() external {
}
receive() payable external {
   currentBalance = currentBalance + msg.value;
}

对于这种新的写法,有几点是要注意的:

  1. fallback 和 receive 不是普通函数,而是新的函数类型,有特别的含义,所以在它们前面加 function 这个关键字。加上 function 之后,它们就变成了一般的函数,只能按一般函数来去调用。

  2. 每个合约最多有一个不带任何参数不带 function 关键字的 fallback 和 receive 函数。

  3. receive 函数类型必须是 payable 的,并且里面的语句只有在通过外部地址往合约里转账的时候执行。 fallback 函数类型可以是 payable 也可以不是 payable 的,如果不是 payable 的,可以往合约发送非转账交易,如果交易里带有转账信息,交易会被 revert;如果是 payable 的,自然也就可以接受转账了。

  4. 尽管 fallback 可以是 payable 的,但并不建议这么做,声明为 payable 之后,其所消耗的 gas 最大量就会被限定在 2300。

0x02 对合约继承更好的支持

这个版本之前合约继承可以这么写的,看起来比较简单,语义上并不是很清晰。

contract Employee {
    function getSalary() public;
}

contract Manager is Employee {
    function increaseSalary() public {

    }
    function getSalary() public {

    }
}

从 0.6 开始,solidity 引入了 abstract, virtual, override 几个关键字,继承关系需要用下面的写法。

abstract contract Employee {
    function getSalary() public virtual;
}

contract Manager is Employee {
    function increaseSalary() public {

    }

    function getSalary() public override {

    }
}

0x03 对 try...catch 机制的支持

在之前的 solidity 版本,我们在当前合约发起对外部合约调用的话,如果外部合约调用执行失败被 revert,外部合约状态会被回滚,当前合约状态也会被回滚。但有时候我们并不想这样,要是能够捕获外部合约调用异常,然后根据情况做自己的处理不是更好么?

// 这是我们需要调用的外部合约接口
interface DataFeed { function getData(address token) external returns (uint value); }

contract FeedConsumer {
    DataFeed feed;
    uint errorCount;
    function rate(address token) public returns (uint value, bool success) {
        // 如果外部合约调用错误次数超过 10 次,就不再进行更多调用了
        require(errorCount &lt; 10);
        try feed.getData(token) returns (uint v) {
            return (v, true);
        } catch Error(string memory /* 出错原因 */) {
            // 这块儿代码只有在对 DataFeed 调用失败时才会执行,通常是不满足外部合约 require 语句条件或触发 revert 语句时所引起的调用失败
            errorCount++;
            return (0, false);
        } catch (bytes memory) {
            // 当外部调用触发 assert 语句或除 0 等比较严重错误时会执行这个 catch 块
            errorCount++;
            return (0, false);
        }
    }
}

0x04 其它

上面只是列了几个比较大的变化,还有一些其它变化也是值得注意的:

  1. 动态数组的长度从 0.6 开始不可更改了。
  2. 开始部分支持数组切片了。
  3. 结构体和枚举类型可以在合约外声明了,之前是只能在合约内声明的。
  4. 如果父合约声明了某个非 private 的状态变量,子合约中就不能再声明同名状态变量。
  5. 从 address 到 address payable 的转换现在可以通过 payable(x) 进行 ,其中 x 必须是 address 类型。

参考资料

【1】https://solidity.readthedocs.io/en/latest/060-breaking-changes.html 【2】https://medium.com/coinmonks/solidity-v0-6-0-is-here-things-you-should-know-7d4ab5bca5f1 【3】https://vomtom.at/solidity-0-6-0-breaking-changes-hands-on-walkthrough/

作者:Ashton 原文链接:https://www.jianshu.com/p/d52c31b14b27

区块链技术网。

  • 发表于 2020-01-15 10:23
  • 阅读 ( 2292 )
  • 学分 ( 95 )
  • 分类:Solidity

评论